library(here)
library(cowplot)
source(here("utils/data_processing.R"))
source(here("utils/figures.R"))

Import data

# Original outputs
df_gpt3.5 <- read_csv(here("data/processed_diagnoses/diagnoses_gpt3.csv.gz"))
df_gpt4.0 <- read_csv(here("data/processed_diagnoses/diagnoses_gpt4.csv.gz"))
df_claude3_haiku_t1.0 <- read_csv(here("data/processed_diagnoses/diagnoses_claude3_haiku_t1.0.csv.gz"))
df_claude3_haiku_t0.1 <- read_csv(here("data/processed_diagnoses/diagnoses_claude3_haiku_t0.1.csv.gz"))
df_claude3_opus_t1.0 <- read_csv(here("data/processed_diagnoses/diagnoses_claude3_opus_t1.0.csv.gz"))
df_gemini1.0_pro_t1.0 <- read_csv(here("data/processed_diagnoses/diagnoses_gemini1.0_pro_t1.0.csv.gz"))
df_gemini1.5_flash_t1.0 <- read_csv(here("data/processed_diagnoses/diagnoses_gemini1.0_pro_t1.0.csv.gz"))
# ICD mapped outputs
#TODO Find source of NAs 
#TODO drop index column in processing script
df_gpt3.5_icd <- read_csv(here("data/processed_diagnoses/diagnoses_gpt3.5_icd.csv.gz")) %>% drop_na() %>% select(-index)
df_gpt4.0_icd <- read_csv(here("data/processed_diagnoses/diagnoses_gpt4_icd.csv.gz")) %>% drop_na() %>% select(-index)
df_claude3_haiku_t1.0_icd <- read_csv(here("data/processed_diagnoses/diagnoses_claude3_haiku_t1.0_icd.csv.gz")) %>% drop_na() %>% select(-index)
df_claude3_opus_t1.0_icd <- read_csv(here("data/processed_diagnoses/diagnoses_claude3_opus_t1.0_icd.csv.gz")) %>% drop_na() %>% select(-index)
df_gemini1.0_pro_t1.0_icd <- read_csv(here("data/processed_diagnoses/diagnoses_gemini1.0_pro_t1.0_icd.csv.gz")) %>% drop_na() %>% select(-index)

Rank abundance

Individual model data

Original responses

rank_abundance_plot(df_gpt3.5)+ggtitle("ChatGPT 3.5")

rank_abundance_plot(df_gpt4.0)+ggtitle("ChatGPT 4.0")

rank_abundance_plot(df_claude3_haiku_t1.0)+ggtitle("Claude3 Haiku t1.0")

rank_abundance_plot(df_claude3_haiku_t0.1)+ggtitle("Claude3 Haiku t0.1")

rank_abundance_plot(df_claude3_opus_t1.0)+ggtitle("Claude3 Opus")

rank_abundance_plot(df_gemini1.0_pro_t1.0)+ggtitle("Gemini 1.0 Pro")

rank_abundance_plot(df_gemini1.5_flash_t1.0)+ggtitle("Gemini 1.5 Flash")

ICD converted responses

rank_abundance_plot(df_gpt3.5_icd)+ggtitle("ChatGPT 3.5 ICD")

rank_abundance_plot(df_gpt4.0_icd)+ggtitle("ChatGPT 4.0 ICD")

rank_abundance_plot(df_claude3_haiku_t1.0_icd)+ggtitle("Claude3 Haiku ICD")

rank_abundance_plot(df_claude3_opus_t1.0_icd)+ggtitle("Claude3 Opus ICD")

rank_abundance_plot(df_gemini1.0_pro_t1.0_icd)+ggtitle("Gemini 1.0 Pro ICD")

Combined model data

Original responses

multi_ranked_abundance_plot(df_gpt3.5, df_gpt4.0, df_claude3_haiku_t1.0, 
                            df_claude3_opus_t1.0, df_gemini1.0_pro_t1.0)+
  ggtitle("Combined model rank abundance")
Warning: Using `size` aesthetic for lines was deprecated in ggplot2 3.4.0.
Please use `linewidth` instead.

ICD converted response

multi_ranked_abundance_plot(df_gpt3.5_icd, df_gpt4.0_icd, df_claude3_haiku_t1.0_icd, 
                            df_claude3_opus_t1.0_icd, df_gemini1.0_pro_t1.0_icd)+
  ggtitle("Combined model ICD rank abundance")

Top diagnoses plots

Individual model data

Original responses

n_diag <- 25
top_diagnosis_plot(df_gpt3.5, n_diag = n_diag)+ggtitle("ChatGPT 3.5")

top_diagnosis_plot(df_gpt4.0, n_diag = n_diag)+ggtitle("ChatGPT 4.0")

top_diagnosis_plot(df_claude3_haiku_t0.1, n_diag = n_diag)+ggtitle("Claude3 Haiku t0.1")

top_diagnosis_plot(df_claude3_haiku_t1.0, n_diag = n_diag)+ggtitle("Claude3 Haiku t1.0")

top_diagnosis_plot(df_claude3_opus_t1.0, n_diag = n_diag)+ggtitle("Claude3 Opus t1.0")

top_diagnosis_plot(df_gemini1.0_pro_t1.0, n_diag = n_diag)+ggtitle("Gemini 1.0 Pro")

top_diagnosis_plot(df_gemini1.5_flash_t1.0, n_diag = n_diag)+ggtitle("Gemini 1.5 Flash")

ICD converted responses

custom_labeler <- function(x, wrap_width=33) {
    x %>%
        str_replace("___.+$", "") %>%
        str_wrap(width = wrap_width)
}

custom_text_formatting <- list(
  theme(axis.text = element_text(size = 7, lineheight = 0.7), 
          strip.text = element_text(size = 7),
          axis.title = element_text(size = 9)),
  tidytext::scale_x_reordered(labels = ~custom_labeler(., wrap_width = 45))
)
n_diag <- 25
top_diagnosis_plot(df_gpt3.5_icd, n_diag = n_diag) + custom_text_formatting + ggtitle("ChatGPT 3.5 ICD") 
Scale for x is already present.
Adding another scale for x, which will replace the existing scale.

top_diagnosis_plot(df_gpt4.0_icd, n_diag = n_diag)+ custom_text_formatting+ggtitle("ChatGPT 4.0 ICD")
Scale for x is already present.
Adding another scale for x, which will replace the existing scale.

top_diagnosis_plot(df_claude3_haiku_t1.0_icd, n_diag = n_diag)+ custom_text_formatting+ggtitle("Claude3 Haiku t1.0 ICD")
Scale for x is already present.
Adding another scale for x, which will replace the existing scale.

top_diagnosis_plot(df_claude3_opus_t1.0_icd, n_diag = n_diag)+ custom_text_formatting+ggtitle("Claude3 Opus t1.0 ICD")
Scale for x is already present.
Adding another scale for x, which will replace the existing scale.

top_diagnosis_plot(df_gemini1.0_pro_t1.0_icd, n_diag = n_diag)+ custom_text_formatting+ggtitle("Gemini 1.0 Pro ICD")
Scale for x is already present.
Adding another scale for x, which will replace the existing scale.

Combined model data

Original responses

multi_top_diagnosis_plot(distribution_vis = "points", wrap_width=45, n_diag = 25,
                         df_gpt3.5, df_gpt4.0, df_claude3_haiku_t1.0, 
                         df_claude3_opus_t1.0, df_gemini1.0_pro_t1.0)
Warning: Duplicated aesthetics after name standardisation: size

ICD converted responses

multi_top_diagnosis_plot(errorbar_type = "range", wrap_width = 33, 
                         df_gpt3.5_icd, df_gpt4.0_icd, df_claude3_haiku_t1.0_icd, 
                         df_claude3_opus_t1.0_icd, df_gemini1.0_pro_t1.0_icd)
Scale for x is already present.
Adding another scale for x, which will replace the existing scale.

Cumulative top frequency plots

Individual model data

Original responses

cumulative_frequency_plot(df_gpt3.5)$plot+ggtitle("GPT3")

cumulative_frequency_plot(df_gpt4.0)$plot+ggtitle("GPT4")

cumulative_frequency_plot(df_claude3_haiku_t1.0)$plot+ggtitle("Claude3 Haiku")

cumulative_frequency_plot(df_claude3_opus_t1.0)$plot+ggtitle("Claude3 Haiku")

cumulative_frequency_plot(df_gemini1.0_pro_t1.0)$plot+ggtitle("Gemini Pro 1.0")

# Example of cumulative frequency values
cumulative_frequency_plot(df_gpt4.0)$data

ICD converted responses

cumulative_frequency_plot(df_gpt3.5_icd)$plot+ggtitle("GPT3 ICD")

cumulative_frequency_plot(df_gpt4.0_icd)$plot+ggtitle("GPT4 ICD")

cumulative_frequency_plot(df_claude3_haiku_t1.0_icd)$plot+ggtitle("Claude3 Haiku ICD")

cumulative_frequency_plot(df_claude3_opus_t1.0_icd)$plot+ggtitle("Claude3 Haiku ICD")

cumulative_frequency_plot(df_gemini1.0_pro_t1.0_icd)$plot+ggtitle("Gemini Pro 1.0 ICD")

Combined model data

Original responses

multi_cumulative_frequency_plot(
    n_diagnoses = 25, distribution_vis = "std_error",
  df_gpt3.5, df_gpt4.0, df_claude3_haiku_t1.0, 
                                df_claude3_opus_t1.0, df_gemini1.0_pro_t1.0)

ICD converted responses

multi_cumulative_frequency_plot(
  n_diagnoses = 25, distribution_vis = "std_error",
  df_gpt3.5_icd, df_gpt4.0_icd, df_claude3_haiku_t1.0_icd, 
                                df_claude3_opus_t1.0_icd, df_gemini1.0_pro_t1.0_icd) +
  ggtitle("ICD converted responses")

Diagnosis rank table

Individual model data

Original responses

diagnosis_rank_table(df_gpt3.5, "mast |mastoc|anaphylaxis") %>% mutate(diagnosis = substr(diagnosis, 1, 60))
diagnosis_rank_table(df_gpt4.0, "mast |mastoc|anaphylaxis") %>% mutate(diagnosis = substr(diagnosis, 1, 60)) 
# diagnosis_rank_table(df_claude3_haiku_t0_1, "mast |mastoc|anaphylaxis") %>% mutate(diagnosis = substr(diagnosis, 1, 60)) 
diagnosis_rank_table(df_claude3_haiku_t1.0, "mast |mastoc|anaphylaxis") %>% mutate(diagnosis = substr(diagnosis, 1, 60)) 
diagnosis_rank_table(df_claude3_opus_t1.0, "mast |mastoc|anaphylaxis") %>% mutate(diagnosis = substr(diagnosis, 1, 60)) 
diagnosis_rank_table(df_gemini1.0_pro_t1.0, "mast |mastoc|anaphylaxis") %>% mutate(diagnosis = substr(diagnosis, 1, 60)) 
diagnosis_rank_table(df_gemini1.5_flash_t1.0, "mast |mastoc|anaphylaxis") %>% mutate(diagnosis = substr(diagnosis, 1, 60)) 

ICD converted responses

diagnosis_rank_table(df_gpt3.5_icd, "mast |mastoc|anaphylaxis") %>% mutate(diagnosis = substr(diagnosis, 1, 60)) 
diagnosis_rank_table(df_gpt4.0_icd, "mast |mastoc|anaphylaxis") %>% mutate(diagnosis = substr(diagnosis, 1, 60)) 
diagnosis_rank_table(df_claude3_haiku_t1.0_icd, "mast |mastoc|anaphylaxis") %>% mutate(diagnosis = substr(diagnosis, 1, 60)) 
diagnosis_rank_table(df_claude3_opus_t1.0_icd, "mast |mastoc|anaphylaxis") %>% mutate(diagnosis = substr(diagnosis, 1, 60)) 
diagnosis_rank_table(df_gemini1.0_pro_t1.0_icd, "mast |mastoc|anaphylaxis") %>% mutate(diagnosis = substr(diagnosis, 1, 60)) 
multi_diagnosis_rank_table <- function(search_pattern, ...){
  listN(...) %>% 
  lapply(., diagnosis_rank_table, pattern = search_pattern) %>%
  mapply(function(x,y) {mutate(x, model=y)}, ., names(.), SIMPLIFY = F) %>% 
  bind_rows() %>% 
  pivot_longer(contains(c("mcas","kawasaki","sle","migraine")), names_to = "criteria", values_to = "rank") %>% 
  filter(grepl("mcas", criteria)) %>% 
  format_models() %>% 
  format_criteria() %>% 
  pivot_wider(names_from = "model", values_from = "rank",names_prefix = "model_") %>% 
  rowwise() %>%
  mutate(mean_rank = round(mean(c_across(contains("model_")), na.rm=T)), 0) %>%
  mutate(ranks = paste(c_across(contains("model_")), collapse = ", ")) %>%
  mutate(output = str_glue("{mean_rank}\n[{ranks}]")) %>%
  select(Diagnosis = diagnosis, criteria, output) %>%
  pivot_wider(names_from = "criteria", values_from = "output")
}

rank_table <- multi_diagnosis_rank_table(search_pattern = "T78\\.2 |D47\\.02 |D89\\.41 |D89\\.49 |D89\\.4 ",
                                         df_gpt3.5_icd, df_gpt4.0_icd, df_claude3_haiku_t1.0_icd, df_claude3_opus_t1.0_icd, df_gemini1.0_pro_t1.0_icd)
rank_table  
rank_table %>% 
  flextable() %>% 
  width(width = 30) %>% 
  align(j = 2:3, align = "center", part = "all")

Diagnosis

MCAS - Consortium

MCAS - Alternative

T78.2 Anaphylactic shock, unspecified

1
[1, 1, 1, 1, 1]

151
[216, 87, 96, 186, 168]

D47.02 Systemic mastocytosis

8
[22, 8, 6, 2, 2]

56
[92, 76, 24, 45, 41]

D89.41 Monoclonal mast cell activation syndrome

40
[128, 23, 28, 11, 11]

61
[141, 68, 23, 39, 36]

D89.49 Other mast cell activation disorder

152
[307, 63, 96, 137, 155]

661
[1156, 557, 176, 383, 1031]

D89.4 Mast cell activation syndrome and related disorders

452
[725, 178, NA, NA, NA]

1380
[NA, 870, 1845, 1424, NA]

NA

Diversity

Individual model data

calculate_diversity_ci <- function(df, b = 100, seed = 1234){
  require(entropart)
  set.seed(seed)
  
  df %>% 
  count(criteria, diagnosis, sort = T) %>% 
  group_by(criteria) %>% 
  nest() %>% 
  mutate(boot = map(data, function(x){
    x <- deframe(x)
    x <- entropart::EntropyCI(entropart::Shannon, 
                              Simulations=b, 
                              Ns = x, q=1, 
                              Correction = "None")
    x
  })) %>% 
  mutate(shannon = map_dbl(data, 
                           ~log(entropart::Diversity(deframe(.), q=1, Correction="None")))) %>% # Calculate shannon with entropart
  mutate(boot = map(boot, ~quantile(., c(0.025,0.5,0.975)))) %>% 
  unnest_wider(boot)
}

plot_diversity_ci <- function(df){
  plt <- df %>% 
    format_criteria() %>% 
    ggplot(aes(x = criteria, y = shannon))+
    geom_point(size = 1)+
    geom_errorbar(aes(ymin = `2.5%`, ymax = `97.5%`), width = 0.3)+
    theme_bw() +
    theme(axis.text.x = element_text(angle = 45, hjust = 1)) +
    labs(x = "", y = "Shannon diversity") 
  return(plt)
}

Original responses

calculate_diversity_ci(df_gpt3.5) %>% plot_diversity_ci() + ggtitle("GPT3")
Loading required package: entropart
=============================================================================================================================================================================================================
=============================================================================================================================================================================================================
=============================================================================================================================================================================================================
=============================================================================================================================================================================================================
=============================================================================================================================================================================================================
=============================================================================================================================================================================================================

calculate_diversity_ci(df_gpt4.0) %>% plot_diversity_ci() + ggtitle("GPT4")
=============================================================================================================================================================================================================
=============================================================================================================================================================================================================
=============================================================================================================================================================================================================
=============================================================================================================================================================================================================
=============================================================================================================================================================================================================
=============================================================================================================================================================================================================

calculate_diversity_ci(df_claude3_haiku_t1.0) %>% plot_diversity_ci() + ggtitle("Claude3 Haiku")
=============================================================================================================================================================================================================
=============================================================================================================================================================================================================
=============================================================================================================================================================================================================
=============================================================================================================================================================================================================
=============================================================================================================================================================================================================
=============================================================================================================================================================================================================

calculate_diversity_ci(df_claude3_opus_t1.0) %>% plot_diversity_ci() + ggtitle("Claude3 Opus")
=============================================================================================================================================================================================================
=============================================================================================================================================================================================================
=============================================================================================================================================================================================================
=============================================================================================================================================================================================================
=============================================================================================================================================================================================================
=============================================================================================================================================================================================================

calculate_diversity_ci(df_gemini1.0_pro_t1.0) %>% plot_diversity_ci() + ggtitle("Gemini t1.0")
=============================================================================================================================================================================================================
=============================================================================================================================================================================================================
=============================================================================================================================================================================================================
=============================================================================================================================================================================================================
=============================================================================================================================================================================================================
=============================================================================================================================================================================================================

Combined model data

Original responses

calculate_shannon <- function(df){
  table(df$criteria, df$diagnosis) %>% 
    vegan::diversity()
}

tibble(model = c("ChatGPT 3.5", "ChatGPT 4.0", "Claude3 Haiku", "Claude3 Opus", "Gemini 1.0 Pro"),
       data = list(df_gpt3.5, df_gpt4.0, df_claude3_haiku_t1.0, df_claude3_opus_t1.0, df_gemini1.0_pro_t1.0)) %>% 
  mutate(shannon = map(data, calculate_shannon)) %>% 
  select(model, shannon) %>% 
  unnest_wider(shannon) %>% 
  pivot_longer(-model, names_to = "criteria", values_to = "shannon") %>% 
  format_criteria() %>% 
  ggplot(aes(x = criteria, y = shannon, color = model))+
  stat_summary(fun.data = mean_se, geom = "errorbar", width = 0.3, aes(group = 1))+
  # geom_boxplot(aes(group = criteria))+
  # geom_jitter(size= 0.5)+
  geom_point(size = 1, position = position_dodge(width = 0.75))+
  theme_bw() +
  scale_color_brewer(palette = "Dark2")+
  theme(axis.text.x = element_text(angle = 45, hjust = 1)) +
  ggpubr::geom_pwc(aes(group = criteria), 
                   method = "wilcox.test",
                   label = "p.signif",
                   p.adjust.method = "BH",
                   hide.ns = T,
                   vjust = 0.5
                   )+
  labs(x = "", y = "Shannon Diversity", color = "")

                   # remove.bracket = T)
                   # symnum.args = list(cutpoints = c(0, 0.0001, 0.001, 0.01, 0.05, 1), 
                   #  symbols = c("****", "***", "**", "*", "ns")))
  # ggpubr::stat_compare_means(comparisons = list(c("SLE - EULAR-ACR", "MCAS - Alternative")))

ICD converted responses

calculate_shannon <- function(df){
  table(df$criteria, df$diagnosis) %>% 
    vegan::diversity()
}

tibble(model = c("ChatGPT 3.5", "ChatGPT 4.0", "Claude3 Haiku", "Claude3 Opus", "Gemini 1.0 Pro"),
       data = list(df_gpt3.5_icd, df_gpt4.0_icd, df_claude3_haiku_t1.0_icd, df_claude3_opus_t1.0_icd, df_gemini1.0_pro_t1.0_icd)) %>% 
  mutate(shannon = map(data, calculate_shannon)) %>% 
  select(model, shannon) %>% 
  unnest_wider(shannon) %>% 
  pivot_longer(-model, names_to = "criteria", values_to = "shannon") %>% 
  format_criteria() %>% 
  ggplot(aes(x = criteria, y = shannon, color = model))+
  stat_summary(fun.data = mean_se, geom = "errorbar", width = 0.3, aes(group = 1))+
  # geom_boxplot(aes(group = criteria))+
  # geom_jitter(size= 0.5)+
  geom_point(size = 1, position = position_dodge(width = 0.75))+
  theme_bw() +
  scale_color_brewer(palette = "Dark2")+
  theme(axis.text.x = element_text(angle = 45, hjust = 1)) +
  ggpubr::geom_pwc(aes(group = criteria), 
                   method = "wilcox.test",
                   label = "p.signif",
                   p.adjust.method = "BH",
                   hide.ns = T,
                   vjust = 0.5
                   )+
  labs(x = "", y = "Shannon Diversity", color = "")

                   # remove.bracket = T)
                   # symnum.args = list(cutpoints = c(0, 0.0001, 0.001, 0.01, 0.05, 1), 
                   #  symbols = c("****", "***", "**", "*", "ns")))
  # ggpubr::stat_compare_means(comparisons = list(c("SLE - EULAR-ACR", "MCAS - Alternative")))

Permutation testing

# Run outside of notebook
# Includes all 10,000 GPT iterations and 1000 bootstrap permutations 
# Contained in script source(here("scripts/diversity_analysis/permute_null_diversity_difference.R"))
library(here)
source(here("utils/data_processing.R"))
library(tidyverse)
library(vegan)
library(broom)
library(here)
library(furrr)
library(future.apply)

model <- "gpt4"
p <- 1000
i <- 10000

print("### Reading data")
read_path <- sprintf("data/processed_diagnoses/diagnoses_%s.csv.gz", model)
df <- read_csv(here(read_path))

print("### Calculating permutation")
perm_out <- difference_permutation_test(df, metric = "precision", permutations = p, gpt_iterations = i)

print("### Writing data")
write_path <- sprintf("data/diversity_analysis/precision_permutation_test_%s_p%s_i%s.RDS", model, p, i)
saveRDS(perm_out, here(write_path))
```r
diagnosis_pca_plot(df_gpt3) + ggtitle(\GPT3\)

<!-- rnb-source-end -->

<!-- rnb-plot-begin -->

<img src="data:image/png;base64,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" />

<!-- rnb-plot-end -->

<!-- rnb-source-begin eyJkYXRhIjoiYGBgclxuYGBgclxuZGlhZ25vc2lzX3BjYV9wbG90KGRmX2dwdDQpICsgZ2d0aXRsZShcXEdQVDRcXClcbmBgYFxuYGBgIn0= -->

```r
```r
diagnosis_pca_plot(df_gpt4) + ggtitle(\GPT4\)

<!-- rnb-source-end -->

<!-- rnb-plot-begin -->

<img src="data:image/png;base64,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" />

<!-- rnb-plot-end -->

<!-- rnb-chunk-end -->


<!-- rnb-chunk-begin -->


<!-- rnb-source-begin eyJkYXRhIjoiYGBgclxucGVybXV0YXRpb25fdGVzdF9wbG90KGRpdmVyc2l0eV9wZXJtdXRhdGlvbl9yZXN1bHRzKVxuYGBgIn0= -->

```r
permutation_test_plot(diversity_permutation_results)

Similarity

Jaccard/Bray curtis

diagnosis_similarity_heatmap(df_gpt3.5, method = "bray")

diagnosis_similarity_heatmap(df_gpt4.0, method = "bray")

diagnosis_similarity_heatmap(df_claude3_haiku_t1.0, method = "bray")

diagnosis_similarity_heatmap(df_claude3_opus_t1.0, method = "bray")

diagnosis_similarity_heatmap(df_gemini1.0_pro_t1.0, method = "bray")

diagnosis_similarity_heatmap(df_gpt3.5_icd, method = "bray")

diagnosis_similarity_heatmap(df_gpt4.0_icd, method = "bray")

diagnosis_similarity_heatmap(df_claude3_haiku_t1.0_icd, method = "bray")

diagnosis_similarity_heatmap(df_claude3_opus_t1.0_icd, method = "bray")

diagnosis_similarity_heatmap(df_gemini1.0_pro_t1.0_icd, method = "bray")

  • Bray-Curtis similarity measures the similarity of a given diagnostic criteria’s set of alternative diagnoses along with their frequencies.
  • This demonstrates that SLE criteria results in a very similar set and frequency of diagnoses, while the diagnoses associated with two MCAS criteria are as different from each other as they are from those generated by the criteria of other conditions.

PCA

diagnosis_pca_plot(df_gpt3.5) + ggtitle("GPT3")

diagnosis_pca_plot(df_gpt4.0) + ggtitle("GPT4")

diagnosis_pca_plot(df_claude3_haiku_t1.0) + ggtitle("Claude Haiku")

diagnosis_pca_plot(df_claude3_opus_t1.0) + ggtitle("Claude Opus")

diagnosis_pca_plot(df_gemini1.0_pro_t1.0) + ggtitle("Gemini")

diagnosis_pca_plot <- function(df){
  df <- format_criteria(df)
  diagnosis_table <- table(df$criteria, df$diagnosis)
  diagnosis_pca <- as.data.frame(diagnosis_table) %>% 
    pivot_wider(names_from = "Var2", values_from = "Freq", values_fill = 0) %>% 
    column_to_rownames("Var1") %>% 
    prcomp()
  
  as.data.frame(diagnosis_pca$x) %>% 
    rownames_to_column("criteria") %>% 
    ggplot(aes(x = PC1, y = PC2, label = criteria))+
    geom_point()+
    ggrepel::geom_label_repel() +
    theme_bw()
}

multi_edge_density_plot <- function(...){
  df_list <- listN(...)
  df_list <- lapply(df_list, ungroup)
  
  # Process data
  df_combined <- df_list %>% 
    mapply(function(x,y) {mutate(x, model=y)}, ., names(.), SIMPLIFY = F) %>% 
    bind_rows() %>% 
    nest(.by = c("model", "criteria")) %>% 
    mutate(edge_density = map_dbl(data, ~edge_density(graph_from_data_frame(.)))) %>% 
    select(-data)
df <- listN(df_gpt3.5_icd, df_gpt4.0_icd, df_claude3_haiku_t1.0_icd, df_claude3_opus_t1.0_icd, df_gemini1.0_pro_t1.0_icd) %>% 
  mapply(function(x,y) {mutate(x, model=y)}, ., names(.), SIMPLIFY = F) %>% 
  bind_rows() %>% 
  count(model, criteria, diagnosis) %>% 
  pivot_wider(names_from = "diagnosis", values_from = "n", values_fill = 0) %>% 
  unite(id, model, criteria, sep = "__") %>% 
  column_to_rownames("id") %>% 
  prcomp(scale. = F)

as.data.frame(df$x) %>% 
    rownames_to_column("id") %>% 
  separate(id, into = c("model", "criteria"), sep = "__") %>% 
  format_criteria() %>% 
  format_models() %>% 
  ggplot(aes(x = PC1, y = PC2, color = criteria))+
    geom_point()+
    # ggrepel::geom_label_repel() +
    theme_bw() +
  scale_color_brewer(palette = "Dark2")

Precision

  • Precision represents how similar each iteration of a 10-point differential diagnosis is with all other differential diagnoses from the same set of criteria.
  • I.e. how reproducible the 10-point differential diagnosis is for each criteria
  • Measured by obtaining the Bray-Curtis similarity values between all iterations within a criteria
# Script for calculating all Bray-Curtis similarity values within a criteria
# Found in source(here("scripts/diversity_analysis/calculate_precision.R"))
library(here)
source(here("utils/data_processing.R"))

models <- c("gpt3", "gpt4", "gpt4_icd")

for (m in models){
  print(sprintf("READING IN DATA FOR: %s", m))
  read_path <- sprintf("data/processed_diagnoses/diagnoses_%s.csv.gz", m)
  df <- read_csv(here(read_path))
  
  print(sprintf("CALCULATING PRECISION FOR: %s", m))
  df <- calculate_precision(df)
  
  print(sprintf("WRITING PRECISION DATA FOR: %s", m))
  out_path <- sprintf("data/diversity_analysis/diagnosis_precision_%s.csv.gz", m)
  write_csv(df, here(out_path))
}
summarise_precision <- function(path){
  df <- vroom::vroom(here(path))
  df %>% 
    mutate(distance = 1-distance) %>% # Convert to similarity
    summarise(mean_cl_normal(distance), .by = criteria)
}



df_precision <- data.frame(model = c("gpt3.5", "gpt4.0", "claude3_haiku_t1.0", "claude3_opus_t1.0", "gemini1.0_pro_t1.0")) %>% 
  mutate(path = map_chr(model, ~str_glue("data/diversity_analysis/diagnosis_precision_{.}_icd.csv.gz"))) %>% mutate(data = map(path, summarise_precision)) %>% 
  select(-path) %>% 
  unnest(data)
df_precision %>% 
  format_criteria() %>% 
  format_models() %>%
  ggplot(aes(x = criteria, y = y))+
  geom_point(aes(color = model), position = position_dodge(width = 0.75))+
  theme_bw()+
  theme(axis.text.x = element_text(angle= 45, hjust = 1))+
  labs(x="", y = "Average Bray-Curtis Similarity") +
  ggpubr::geom_pwc(method = "wilcox.test", p.adjust.method = "BH", hide.ns = T, label = "p.adj.signif", bracket.nudge.y = 0.3, vjust = 0.6, step.increase = 0.14, tip.length = 0.02) +
  ylim(c(0,1)) +
  labs(color=NULL)+
  scale_color_brewer(palette = "Dark2")

df_precision <- vroom::vroom(here("data/diversity_analysis/diagnosis_precision_gpt4.csv.gz"))
df_precision_summary <- df_precision %>% 
  mutate(distance = 1-distance) %>% # Convert to similarity
  summarise(mean_cl_normal(distance), .by = criteria)
df_precision_summary
calculate_boxplot_stats <- function(df){
  df %>% 
    nest(data = distance, .by = criteria) %>% 
    mutate(box = map(data, function(df){
      x <- boxplot.stats(df$distance)$stats
      x <- sort(x)
      names(x) <- c("min","lower","median","upper","max")
      return(x)
    })) %>% 
    select(-data) %>% 
    unnest_wider(box)
}



manual_box_plot <- function(df, width = 0.9){
  df %>% 
    format_criteria() %>% 
    ggplot(aes(
      x = criteria,
      ymin = min,
      lower = lower,
      middle = median,
      upper = upper,
      ymax = max
    ))+
    geom_boxplot(stat = "identity", width = width) +
    theme_bw() +
    theme(axis.text.x = element_text(angle = 45, hjust = 1))+
    labs(x = "", y = "Bray-Curtis similarity")
}
df_precision_stats <- df_precision %>% 
  mutate(distance = 1-distance) %>% # Convert to similarity
  calculate_boxplot_stats()
df_precision_stats
# Run outside of notebook
# Tried multiple combinations of bootstrap permutations and gpt_iterations
# Because a single bray-curtis matrix of all 10,000 comparisons takes ~10 minutes
# Contained in following script:
# source(here(\scripts/diversity_analysis/permute_null_precision_difference.R\))
model <- \gpt4\
p <- 1000
i <- 10000

print(\### Reading data\)
read_path <- sprintf(\data/processed_diagnoses/diagnoses_%s.csv.gz\, model)
df <- read_csv(here(read_path))

print(\### Calculating permutation\)
perm_out <- difference_permutation_test(df, metric = \precision\, permutations = p, gpt_iterations = i)

print(\### Writing data\)
write_path <- sprintf(\data/diversity_analysis/precision_permutation_test_%s_p%s_i%s.RDS\, model, p, i)
saveRDS(perm_out, here())

Permutation testing

# Run outside of notebook
# Tried multiple combinations of bootstrap permutations and gpt_iterations
# Because a single bray-curtis matrix of all 10,000 comparisons takes ~10 minutes
# Contained in following script:
# source(here("scripts/diversity_analysis/permute_null_precision_difference.R"))
model <- "gpt4"
p <- 1000
i <- 10000

print("### Reading data")
read_path <- sprintf("data/processed_diagnoses/diagnoses_%s.csv.gz", model)
df <- read_csv(here(read_path))

print("### Calculating permutation")
perm_out <- difference_permutation_test(df, metric = "precision", permutations = p, gpt_iterations = i)

print("### Writing data")
write_path <- sprintf("data/diversity_analysis/precision_permutation_test_%s_p%s_i%s.RDS", model, p, i)
saveRDS(perm_out, here())
readRDS(here("data/diversity_analysis/precision_permutation_test_gpt4_p1000_i10000.RDS"))
readRDS(here("data/diversity_analysis/precision_permutation_test_gpt4_p1000_i10000.RDS")) %>% permutation_test_plot()

iNEXT

```r
ggsave(plot=plt_top,filename=here(\figures/3_Top_25_diagnoses.pdf\), width = 7.4, height = 6.5)

<!-- rnb-source-end -->

<!-- rnb-chunk-end -->


<!-- rnb-text-begin -->



# Final figures

### 2_Top_diagnoses

<!-- rnb-text-end -->


<!-- rnb-chunk-begin -->


<!-- rnb-source-begin eyJkYXRhIjoiYGBgclxuY3VzdG9tX2xhYmVsZXIgPC0gZnVuY3Rpb24oeCwgd3JhcF93aWR0aD0zMykge1xuICAgIHggJT4lXG4gICAgICAgIHN0cl9yZXBsYWNlKFwiX19fLiskXCIsIFwiXCIpICU+JVxuICAgICAgICBzdHJfd3JhcCh3aWR0aCA9IHdyYXBfd2lkdGgpXG59XG5cbnBsdF90b3AgPC0gdG9wX2RpYWdub3Npc19wbG90KGRmX2dwdDQsIG5fZGlhZyA9IDI1KSArIFxuICB0aGVtZShheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDUsIGxpbmVoZWlnaHQgPSAwLjcpLCBcbiAgICAgICAgc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gNyksXG4gICAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDkpKSArIFxuICB0aWR5dGV4dDo6c2NhbGVfeF9yZW9yZGVyZWQobGFiZWxzID0gY3VzdG9tX2xhYmVsZXIpXG5wbHRfdG9wXG5gYGAifQ== -->

```r
custom_labeler <- function(x, wrap_width=33) {
    x %>%
        str_replace("___.+$", "") %>%
        str_wrap(width = wrap_width)
}

plt_top <- top_diagnosis_plot(df_gpt4, n_diag = 25) + 
  theme(axis.text = element_text(size = 5, lineheight = 0.7), 
        strip.text = element_text(size = 7),
        axis.title = element_text(size = 9)) + 
  tidytext::scale_x_reordered(labels = custom_labeler)
plt_top
ggsave(plot=plt_top,filename=here("figures/3_Top_25_diagnoses.pdf"), width = 7.4, height = 6.5)

3A_Rank_abundance

```r
plt_div <- df_diversity_ci %>% 
  format_criteria() %>% 
  ggplot(aes(x = criteria, y = shannon))+
  geom_point(size = 1)+
  geom_errorbar(aes(ymin = `2.5%`, ymax = `97.5%`), width = 0.3)+
  theme_bw() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1)) +
  labs(x = \\, y = \Shannon diversity\) 
plt_div

<!-- rnb-source-end -->

<!-- rnb-plot-begin -->

<img src="data:image/png;base64,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" />

<!-- rnb-plot-end -->

<!-- rnb-chunk-end -->


<!-- rnb-text-begin -->


### 3B_Cumulative_frequency


<!-- rnb-text-end -->


<!-- rnb-chunk-begin -->


<!-- rnb-source-begin eyJkYXRhIjoiYGBgclxucGx0X2N1bXVsYXRpdmUgPC0gY3VtdWxhdGl2ZV9mcmVxdWVuY3lfcGxvdChkZl9ncHQ0KSArXG4gIGxhYnMoeSA9IFwiQ29tYmluZWQgZnJlcXVlbmN5XFxub2YgdG9wIDI1IGRpYWdub3Nlc1wiKVxucGx0X2N1bXVsYXRpdmVcbmBgYCJ9 -->

```r
plt_cumulative <- cumulative_frequency_plot(df_gpt4) +
  labs(y = "Combined frequency\nof top 25 diagnoses")
plt_cumulative

3C_Diversity

plt_div <- df_diversity_ci %>% 
  format_criteria() %>% 
  ggplot(aes(x = criteria, y = shannon))+
  geom_point(size = 1)+
  geom_errorbar(aes(ymin = `2.5%`, ymax = `97.5%`), width = 0.3)+
  theme_bw() +
  theme(axis.text.x = element_text(angle = 45, hjust = 1)) +
  labs(x = "", y = "Shannon diversity") 
plt_div

3D_Precision

plt_precision <- manual_box_plot(df_precision_stats)
plt_precision

3_Compiled

plt_fig3 <- plot_grid(
  plot_grid(NULL),
  plot_grid(
    plt_rank,
    NULL,
    plt_cumulative,
    nrow = 1, 
    rel_widths = c(3,0.2,2),
    labels = c("A", "", "B"),
    vjust = 0.2
  ),
  plot_grid(NULL),
  plot_grid(
    plt_div,
    NULL,
    plt_precision,
    nrow = 1,
    rel_widths = c(1,0.1,1),
    labels = c("C", "", "D"),
    vjust = 0.2
  ),
  ncol = 1,
  rel_heights = c(0.05,1,0.05,1)
)
plt_fig3
ggsave(plot=plt_fig3,filename=here("figures/4_Diagnosis_diversity.pdf"), width = 6.5, height = 6)

Table

diagnosis_rank_table(df_gpt4, "mast |mastoc|anaphylaxis") %>% mutate(diagnosis = substr(diagnosis, 1, 60)) %>% 
  select(contains(c("diagnosis","mcas"))) %>% 
  head(6) %>% 
  mutate(diagnosis = str_to_sentence(diagnosis)) %>% 
  rename(Diagnosis = diagnosis, `MCAS consortium` = mcas_consortium, `MCAS alternative` = mcas_alternative) %>% 
  flextable() %>% 
  width(width = 2) %>% 
  align(j = 2:3, align = "center", part = "all") %>% 
  {print(., preview = "pdf");.}

Supplemental figures

plot_grid(
  top_diagnosis_plot(df_gpt3, n_diag = 25) + 
    theme(axis.text = element_text(size = 4.5, lineheight = 0.7), 
          strip.text = element_text(size = 7),
          axis.title = element_text(size = 9)) + 
    tidytext::scale_x_reordered(labels = custom_labeler),
  
  top_diagnosis_plot(df_gpt4_icd, n_diag = 25) + 
    theme(axis.text = element_text(size = 4, lineheight = 0.7), 
          strip.text = element_text(size = 7),
          axis.title = element_text(size = 9)) + 
    tidytext::scale_x_reordered(labels = ~custom_labeler(., wrap_width = 45)),
  ncol = 1,
  rel_heights = c(0.9,1),
  labels = c("A","B")
) %>% 
  {ggsave(plot=.,filename=here("figures/S_Top_diagnoses.pdf"), width = 7, height = 10);.}
plot_grid(
  rank_abundance_plot(df_gpt3) +theme(legend.position = c(0.7,0.7)),
  rank_abundance_plot(df_gpt4_icd) +theme(legend.position = c(0.7,0.7)),
  nrow = 1,
  labels = c("A","B")
) %>% 
  {ggsave(plot=.,filename=here("figures/S_Ranked_abundance.pdf"), width = 7.5, height = 3);.}

Alternative combined figure

n_diagnoses_bar <- 15
n_diagnoses_abundance <- 50
n_diagnoses_cumulative <- 50

apply_text_formatting <- list(theme(
  axis.text = element_text(size = 6),
  axis.title = element_text(size = 9),
  legend.text = element_text(size = 6),
  # legend.spacing.y = unit(0.1, 'cm')
  # legend.height = unit(0.1, 'cm'),
  legend.key.height = unit(0.3, 'cm')
  # legend.key.spacing = unit(0.1, 'cm')
  ))
  
  
plot_grid(
  
  ###
  top_diagnosis_plot(df_gpt4, n_diag = n_diagnoses_bar) + 
    theme(axis.text = element_text(size = 5, lineheight = 0.7), 
          strip.text = element_text(size = 7),
          axis.title = element_text(size = 9)) + 
    tidytext::scale_x_reordered(labels = custom_labeler),
  ###
  NULL,
  plot_grid(
    plot_grid(NULL),
    plot_grid(
      NULL,
      ####
      rank_abundance_plot(df_gpt4, n_diagnoses = n_diagnoses_abundance) +theme(legend.position = c(0.7,0.7)) + apply_text_formatting,
      ###
      NULL,
      ###
      cumulative_frequency_plot(df_gpt4, n_diagnoses = n_diagnoses_cumulative) + labs(y = str_glue("Combined frequency\nof top {n_diagnoses_cumulative} diagnoses")) + apply_text_formatting,
      ###
      NULL,
      nrow = 1, 
      rel_widths = c(0.2, 2.5, 0.2, 2, 0.2 ),
      # labels = c("A", "", "B"),
      vjust = 0.2
    ),
    plot_grid(NULL),
    plot_grid(
      NULL,
      ###
       df_diversity_ci %>% 
        format_criteria() %>% 
        ggplot(aes(x = criteria, y = shannon))+
        geom_point(size = 1)+
        geom_errorbar(aes(ymin = `2.5%`, ymax = `97.5%`), width = 0.3)+
        theme_bw() +
        theme(axis.text.x = element_text(angle = 45, hjust = 1)) +
        labs(x = "", y = "Shannon\ndiversity") + apply_text_formatting,
      ###
      NULL,
      ###
      manual_box_plot(df_precision_stats) + labs(y='Bray-Curtis\nsimilarity') + apply_text_formatting,
      ###
      NULL,
      nrow = 1,
      rel_widths = c(0.2, 1, 0.1, 1, 0.2),
      # labels = c("C", "", "D"),
      vjust = 0.2
    ),
    ncol = 1,
    rel_heights = c(0.05,1,0.05,1)
  ),
  
  ncol = 1,
  rel_heights = c(0.9,0.02,1)
) %>% 
  {ggsave(plot=.,filename=here("figures/3_4_combined.pdf"), width = 7, height = 9);.}
n_diagnoses_bar <- 15
n_diagnoses_abundance <- 50
n_diagnoses_cumulative <- 50

apply_text_formatting <- list(theme(
  axis.text = element_text(size = 6),
  axis.title = element_text(size = 9),
  legend.text = element_text(size = 6),
  # legend.spacing.y = unit(0.1, 'cm')
  # legend.height = unit(0.1, 'cm'),
  legend.key.height = unit(0.3, 'cm')
  # legend.key.spacing = unit(0.1, 'cm')
  ))
  
  
plot_grid(
  
  ###
  top_diagnosis_plot(df_gpt4, n_diag = n_diagnoses_bar) + 
    theme(axis.text = element_text(size = 5, lineheight = 0.7), 
          strip.text = element_text(size = 7),
          axis.title = element_text(size = 9)) + 
    tidytext::scale_x_reordered(labels = custom_labeler),
  ###
  NULL,
  plot_grid(
      rank_abundance_plot(df_gpt4, n_diagnoses = n_diagnoses_abundance) +theme(legend.position = c(0.7,0.7)) + apply_text_formatting,
      cumulative_frequency_plot(df_gpt4, n_diagnoses = n_diagnoses_cumulative, width = 0.75) + labs(y = str_glue("Combined frequency\nof top {n_diagnoses_cumulative} diagnoses")) + apply_text_formatting,
      df_diversity_ci %>% 
        format_criteria() %>% 
        ggplot(aes(x = criteria, y = shannon))+
        geom_point(size = 1)+
        geom_errorbar(aes(ymin = `2.5%`, ymax = `97.5%`), width = 0.3)+
        theme_bw() +
        theme(axis.text.x = element_text(angle = 45, hjust = 1)) +
        labs(x = "", y = "Shannon diversity") + apply_text_formatting,
      manual_box_plot(df_precision_stats, width = 0.5) + labs(y='Bray-Curtis similarity') + apply_text_formatting,
      nrow = 1, 
      axis = 'tb',
      align = 'h',
      rel_widths = c(1, 0.7, 0.7, 0.7),
      labels = c(LETTERS[2:5]),
      vjust = 0.2
    ),
  ncol = 1,
  rel_heights = c(1, 0.05, 0.65),
  labels = c("A","","")
)  
Error in count(., criteria, diagnosis, sort = T) : 
  object 'df_gpt4' not found

Alternative final for ICD

n_diagnoses_bar <- 10
n_diagnoses_abundance <- 50
n_diagnoses_cumulative <- 50

title_size <- 9
label_size <- 6
legend_x_pad <- 4
legend_y_pad <- 2

apply_text_formatting <- list(theme(
  axis.text = element_text(size = label_size),
  axis.title = element_text(size = title_size),
  legend.text = element_text(size = label_size),
  strip.text = element_text(size = label_size+1),
  legend.key.height = unit(0.4, 'cm'),
  legend.box.background = element_rect(color = "black", size = 1),
  legend.margin = margin(t = legend_y_pad, r = legend_x_pad, b = legend_y_pad, l = legend_x_pad*1.1),
  legend.spacing.x = unit(0, 'cm'),                           # Horizontal spacing between legend items
  # legend.spacing.y = unit(0, 'cm'),
  # legend.box.spacing = unit(0, "cm")
  ))

strip_margin <- 1
strip_formatting <- list(theme(
  strip.text.x = element_text(margin = margin(t = strip_margin, r = strip_margin, b = strip_margin, l = strip_margin)), 
  strip.text.y = element_text(margin = margin(t = strip_margin, r = strip_margin, b = strip_margin, l = strip_margin))
  # strip.background = element_rect(margin = margin(t = strip_margin, r = strip_margin, b = strip_margin, l = strip_margin))
))

plt_diags <- multi_top_diagnosis_plot(distribution_vis = "points", wrap_width=58, n_diag = n_diagnoses_bar,
                         df_gpt3.5_icd, df_gpt4.0_icd, df_claude3_haiku_t1.0_icd, 
                         df_claude3_opus_t1.0_icd, df_gemini1.0_pro_t1.0_icd) +
  theme(legend.position = "bottom", legend.direction = "horizontal") +
  apply_text_formatting +
  theme(axis.text.y = element_text(size = 6.5)) +
  strip_formatting +
  # theme(legend.position = c(-1,0))+
  theme(panel.spacing = unit(0, "lines")) +
  guides(
  color = guide_legend(override.aes = list(size = 2))  # Increase the point size in the legend
)
  

plt_rank <- multi_ranked_abundance_plot(df_gpt3.5_icd, df_gpt4.0_icd, df_claude3_haiku_t1.0_icd, 
                            df_claude3_opus_t1.0_icd, df_gemini1.0_pro_t1.0_icd)+
  theme(legend.position = "bottom", legend.direction = "horizontal") +
  apply_text_formatting+
  guides(color = guide_legend(ncol = 2))

plt_cumulative <- multi_cumulative_frequency_plot(n_diagnoses = n_diagnoses_cumulative, distribution_vis = "points",
                                                  df_gpt3.5_icd, df_gpt4.0_icd, df_claude3_haiku_t1.0_icd, 
                                df_claude3_opus_t1.0_icd, df_gemini1.0_pro_t1.0_icd) +
  theme(legend.position = "bottom", legend.direction = "horizontal") +
  apply_text_formatting+
  guides(color = guide_legend(ncol = 2)) +
  labs(y = "Combined frequency\nof top 50 diagnoses", x = NULL)

plt_shannon <- tibble(model = c("ChatGPT 3.5", "ChatGPT 4.0", "Claude3 Haiku", "Claude3 Opus", "Gemini 1.0 Pro"),
       data = list(df_gpt3.5_icd, df_gpt4.0_icd, df_claude3_haiku_t1.0_icd, df_claude3_opus_t1.0_icd, df_gemini1.0_pro_t1.0_icd)) %>% 
  mutate(shannon = map(data, calculate_shannon)) %>% 
  select(model, shannon) %>% 
  unnest_wider(shannon) %>% 
  pivot_longer(-model, names_to = "criteria", values_to = "shannon") %>% 
  format_criteria() %>% 
  ggplot(aes(x = criteria, y = shannon))+
  stat_summary(fun.y = mean, aes(group = criteria), geom = "crossbar", size = 0.3, width = 0.75) +
  geom_point(aes(color = model), size = 0.5, position = position_dodge(width = 0.75))+
  theme_bw() +
  scale_color_brewer(palette = "Dark2")+
  theme(axis.text.x = element_text(angle = 45, hjust = 1)) +
  ggpubr::geom_pwc(aes(group = criteria), 
                   method = "wilcox.test", 
                   p.adjust.method = "BH", 
                   hide.ns = T, 
                   label = "p.adj.signif", 
                   bracket.nudge.y = 0.1, 
                   vjust = 0.6, 
                   step.increase = 0.14, 
                   tip.length = 0.02
                   )+
  labs(x = NULL, y = "Shannon Diversity", color = "")+
  apply_text_formatting+
  theme(legend.position = "bottom", legend.direction = "horizontal") +
  guides(color = guide_legend(ncol = 2))

plt_precision <- df_precision %>% 
  format_criteria() %>% 
  format_models() %>%
  ggplot(aes(x = criteria, y = y))+
    stat_summary(fun.y = mean, aes(group = criteria), geom = "crossbar", size = 0.3, width = 0.75) +
  geom_point(aes(color = model), size = 0.5, position = position_dodge(width = 0.75))+
  theme_bw()+
  theme(axis.text.x = element_text(angle= 45, hjust = 1))+
  labs(x=NULL, y = "Average Bray-Curtis\nSimilarity") +
  ggpubr::geom_pwc(method = "wilcox.test", p.adjust.method = "BH", hide.ns = T, label = "p.adj.signif", bracket.nudge.y = 0.3, vjust = 0.6, step.increase = 0.14, tip.length = 0.02) +
  ylim(c(0,1)) +
  labs(color=NULL)+
  scale_color_brewer(palette = "Dark2") +
  theme(legend.position = "none")+
  apply_text_formatting




full_plt <- plot_grid(
  
  ###
  plt_diags,
  ###
  NULL,
  plot_grid(
      plt_rank,
      plt_cumulative,
      plt_shannon,
      plt_precision,
      nrow = 1, 
      axis = 'tb',
      align = 'h',
      rel_widths = c(1, 0.7, 0.7, 0.7),
      labels = c(LETTERS[2:5]),
      vjust = 0.2
    ),
  ncol = 1,
  rel_heights = c(1.2, 0.05, 0.65),
  labels = c("A","","")
)  

full_plt

Things to fix - Legend position for C-E - Legend width for B - Move legend for A to the left of “Frequency?” - Rank plot line weight

ggsave(plot=full_plt,filename=here("figures/3_diagnosis_diversity.pdf"), width = 7.5, height = 7.5)

set_table_properties(opts_pdf = list(tabcolsep = 0))

set_flextable_defaults(fonts_ignore=TRUE)

multi_diagnosis_rank_table(search_pattern = "T78\\.2 |D47\\.02 |D89\\.41 |D89\\.49 |D89\\.4 ",
                                         df_gpt3.5_icd, df_gpt4.0_icd, df_claude3_haiku_t1.0_icd, df_claude3_opus_t1.0_icd, df_gemini1.0_pro_t1.0_icd) %>% 
  flextable() %>% 
  width(width = 2) %>% 
  fontsize(size = 9) %>% 
  fontsize(size = 10, part = "header") %>% 
  padding(padding = 0) %>% 
  align(j = 2:3, align = "center", part = "all") %>% 
  set_table_properties(opts_pdf = list(arraystretch = 1.25)) %>% 
  {print(., preview = "pdf");.}

Diagnosis

MCAS - Consortium

MCAS - Alternative

T78.2 Anaphylactic shock, unspecified

1
[1, 1, 1, 1, 1]

151
[216, 87, 96, 186, 168]

D47.02 Systemic mastocytosis

8
[22, 8, 6, 2, 2]

56
[92, 76, 24, 45, 41]

D89.41 Monoclonal mast cell activation syndrome

40
[128, 23, 28, 11, 11]

61
[141, 68, 23, 39, 36]

D89.49 Other mast cell activation disorder

152
[307, 63, 96, 137, 155]

661
[1156, 557, 176, 383, 1031]

D89.4 Mast cell activation syndrome and related disorders

452
[725, 178, NA, NA, NA]

1380
[NA, 870, 1845, 1424, NA]

LS0tCnRpdGxlOiAiRGlhZ25vc2lzIGRpc3RyaWJ1dGlvbiBhbmFseXNpcyIKb3V0cHV0OiAKICBodG1sX25vdGVib29rOgogICAgdG9jOiB0cnVlCiAgICB0b2NfZmxvYXQ6IHRydWUKLS0tCgpgYGB7ciwgbWVzc2FnZSA9IEZ9CmxpYnJhcnkoaGVyZSkKbGlicmFyeShjb3dwbG90KQpzb3VyY2UoaGVyZSgidXRpbHMvZGF0YV9wcm9jZXNzaW5nLlIiKSkKc291cmNlKGhlcmUoInV0aWxzL2ZpZ3VyZXMuUiIpKQpgYGAKCiMgSW1wb3J0IGRhdGEKYGBge3IsIG1lc3NhZ2U9Rn0KIyBPcmlnaW5hbCBvdXRwdXRzCmRmX2dwdDMuNSA8LSByZWFkX2NzdihoZXJlKCJkYXRhL3Byb2Nlc3NlZF9kaWFnbm9zZXMvZGlhZ25vc2VzX2dwdDMuY3N2Lmd6IikpCmRmX2dwdDQuMCA8LSByZWFkX2NzdihoZXJlKCJkYXRhL3Byb2Nlc3NlZF9kaWFnbm9zZXMvZGlhZ25vc2VzX2dwdDQuY3N2Lmd6IikpCmRmX2NsYXVkZTNfaGFpa3VfdDEuMCA8LSByZWFkX2NzdihoZXJlKCJkYXRhL3Byb2Nlc3NlZF9kaWFnbm9zZXMvZGlhZ25vc2VzX2NsYXVkZTNfaGFpa3VfdDEuMC5jc3YuZ3oiKSkKZGZfY2xhdWRlM19oYWlrdV90MC4xIDwtIHJlYWRfY3N2KGhlcmUoImRhdGEvcHJvY2Vzc2VkX2RpYWdub3Nlcy9kaWFnbm9zZXNfY2xhdWRlM19oYWlrdV90MC4xLmNzdi5neiIpKQpkZl9jbGF1ZGUzX29wdXNfdDEuMCA8LSByZWFkX2NzdihoZXJlKCJkYXRhL3Byb2Nlc3NlZF9kaWFnbm9zZXMvZGlhZ25vc2VzX2NsYXVkZTNfb3B1c190MS4wLmNzdi5neiIpKQpkZl9nZW1pbmkxLjBfcHJvX3QxLjAgPC0gcmVhZF9jc3YoaGVyZSgiZGF0YS9wcm9jZXNzZWRfZGlhZ25vc2VzL2RpYWdub3Nlc19nZW1pbmkxLjBfcHJvX3QxLjAuY3N2Lmd6IikpCmRmX2dlbWluaTEuNV9mbGFzaF90MS4wIDwtIHJlYWRfY3N2KGhlcmUoImRhdGEvcHJvY2Vzc2VkX2RpYWdub3Nlcy9kaWFnbm9zZXNfZ2VtaW5pMS4wX3Byb190MS4wLmNzdi5neiIpKQpgYGAKCmBgYHtyLCBtZXNzYWdlID0gRn0KIyBJQ0QgbWFwcGVkIG91dHB1dHMKI1RPRE8gRmluZCBzb3VyY2Ugb2YgTkFzIAojVE9ETyBkcm9wIGluZGV4IGNvbHVtbiBpbiBwcm9jZXNzaW5nIHNjcmlwdApkZl9ncHQzLjVfaWNkIDwtIHJlYWRfY3N2KGhlcmUoImRhdGEvcHJvY2Vzc2VkX2RpYWdub3Nlcy9kaWFnbm9zZXNfZ3B0My41X2ljZC5jc3YuZ3oiKSkgJT4lIGRyb3BfbmEoKSAlPiUgc2VsZWN0KC1pbmRleCkKZGZfZ3B0NC4wX2ljZCA8LSByZWFkX2NzdihoZXJlKCJkYXRhL3Byb2Nlc3NlZF9kaWFnbm9zZXMvZGlhZ25vc2VzX2dwdDRfaWNkLmNzdi5neiIpKSAlPiUgZHJvcF9uYSgpICU+JSBzZWxlY3QoLWluZGV4KQpkZl9jbGF1ZGUzX2hhaWt1X3QxLjBfaWNkIDwtIHJlYWRfY3N2KGhlcmUoImRhdGEvcHJvY2Vzc2VkX2RpYWdub3Nlcy9kaWFnbm9zZXNfY2xhdWRlM19oYWlrdV90MS4wX2ljZC5jc3YuZ3oiKSkgJT4lIGRyb3BfbmEoKSAlPiUgc2VsZWN0KC1pbmRleCkKZGZfY2xhdWRlM19vcHVzX3QxLjBfaWNkIDwtIHJlYWRfY3N2KGhlcmUoImRhdGEvcHJvY2Vzc2VkX2RpYWdub3Nlcy9kaWFnbm9zZXNfY2xhdWRlM19vcHVzX3QxLjBfaWNkLmNzdi5neiIpKSAlPiUgZHJvcF9uYSgpICU+JSBzZWxlY3QoLWluZGV4KQpkZl9nZW1pbmkxLjBfcHJvX3QxLjBfaWNkIDwtIHJlYWRfY3N2KGhlcmUoImRhdGEvcHJvY2Vzc2VkX2RpYWdub3Nlcy9kaWFnbm9zZXNfZ2VtaW5pMS4wX3Byb190MS4wX2ljZC5jc3YuZ3oiKSkgJT4lIGRyb3BfbmEoKSAlPiUgc2VsZWN0KC1pbmRleCkKYGBgCgoKIyBSYW5rIGFidW5kYW5jZQoKIyMgSW5kaXZpZHVhbCBtb2RlbCBkYXRhCgojIyMgT3JpZ2luYWwgcmVzcG9uc2VzCmBgYHtyfQpyYW5rX2FidW5kYW5jZV9wbG90KGRmX2dwdDMuNSkrZ2d0aXRsZSgiQ2hhdEdQVCAzLjUiKQpyYW5rX2FidW5kYW5jZV9wbG90KGRmX2dwdDQuMCkrZ2d0aXRsZSgiQ2hhdEdQVCA0LjAiKQpyYW5rX2FidW5kYW5jZV9wbG90KGRmX2NsYXVkZTNfaGFpa3VfdDEuMCkrZ2d0aXRsZSgiQ2xhdWRlMyBIYWlrdSB0MS4wIikKcmFua19hYnVuZGFuY2VfcGxvdChkZl9jbGF1ZGUzX2hhaWt1X3QwLjEpK2dndGl0bGUoIkNsYXVkZTMgSGFpa3UgdDAuMSIpCnJhbmtfYWJ1bmRhbmNlX3Bsb3QoZGZfY2xhdWRlM19vcHVzX3QxLjApK2dndGl0bGUoIkNsYXVkZTMgT3B1cyIpCnJhbmtfYWJ1bmRhbmNlX3Bsb3QoZGZfZ2VtaW5pMS4wX3Byb190MS4wKStnZ3RpdGxlKCJHZW1pbmkgMS4wIFBybyIpCnJhbmtfYWJ1bmRhbmNlX3Bsb3QoZGZfZ2VtaW5pMS41X2ZsYXNoX3QxLjApK2dndGl0bGUoIkdlbWluaSAxLjUgRmxhc2giKQpgYGAKCiMjIyBJQ0QgY29udmVydGVkIHJlc3BvbnNlcwpgYGB7cn0KcmFua19hYnVuZGFuY2VfcGxvdChkZl9ncHQzLjVfaWNkKStnZ3RpdGxlKCJDaGF0R1BUIDMuNSBJQ0QiKQpyYW5rX2FidW5kYW5jZV9wbG90KGRmX2dwdDQuMF9pY2QpK2dndGl0bGUoIkNoYXRHUFQgNC4wIElDRCIpCnJhbmtfYWJ1bmRhbmNlX3Bsb3QoZGZfY2xhdWRlM19oYWlrdV90MS4wX2ljZCkrZ2d0aXRsZSgiQ2xhdWRlMyBIYWlrdSBJQ0QiKQpyYW5rX2FidW5kYW5jZV9wbG90KGRmX2NsYXVkZTNfb3B1c190MS4wX2ljZCkrZ2d0aXRsZSgiQ2xhdWRlMyBPcHVzIElDRCIpCnJhbmtfYWJ1bmRhbmNlX3Bsb3QoZGZfZ2VtaW5pMS4wX3Byb190MS4wX2ljZCkrZ2d0aXRsZSgiR2VtaW5pIDEuMCBQcm8gSUNEIikKYGBgCgojIyBDb21iaW5lZCBtb2RlbCBkYXRhCgojIyMgT3JpZ2luYWwgcmVzcG9uc2VzCgpgYGB7cn0KbXVsdGlfcmFua2VkX2FidW5kYW5jZV9wbG90KGRmX2dwdDMuNSwgZGZfZ3B0NC4wLCBkZl9jbGF1ZGUzX2hhaWt1X3QxLjAsIAogICAgICAgICAgICAgICAgICAgICAgICAgICAgZGZfY2xhdWRlM19vcHVzX3QxLjAsIGRmX2dlbWluaTEuMF9wcm9fdDEuMCkrCiAgZ2d0aXRsZSgiQ29tYmluZWQgbW9kZWwgcmFuayBhYnVuZGFuY2UiKQpgYGAKIyMjIElDRCBjb252ZXJ0ZWQgcmVzcG9uc2UgCmBgYHtyfQptdWx0aV9yYW5rZWRfYWJ1bmRhbmNlX3Bsb3QoZGZfZ3B0My41X2ljZCwgZGZfZ3B0NC4wX2ljZCwgZGZfY2xhdWRlM19oYWlrdV90MS4wX2ljZCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZl9jbGF1ZGUzX29wdXNfdDEuMF9pY2QsIGRmX2dlbWluaTEuMF9wcm9fdDEuMF9pY2QpKwogIGdndGl0bGUoIkNvbWJpbmVkIG1vZGVsIElDRCByYW5rIGFidW5kYW5jZSIpCmBgYAoKIyBUb3AgZGlhZ25vc2VzIHBsb3RzCgojIyBJbmRpdmlkdWFsIG1vZGVsIGRhdGEKCiMjIyBPcmlnaW5hbCByZXNwb25zZXMKCmBgYHtyLCBmaWcud2lkdGggPSAxNiwgZmlnLmhlaWdodCA9IDh9Cm5fZGlhZyA8LSAyNQp0b3BfZGlhZ25vc2lzX3Bsb3QoZGZfZ3B0My41LCBuX2RpYWcgPSBuX2RpYWcpK2dndGl0bGUoIkNoYXRHUFQgMy41IikKdG9wX2RpYWdub3Npc19wbG90KGRmX2dwdDQuMCwgbl9kaWFnID0gbl9kaWFnKStnZ3RpdGxlKCJDaGF0R1BUIDQuMCIpCnRvcF9kaWFnbm9zaXNfcGxvdChkZl9jbGF1ZGUzX2hhaWt1X3QwLjEsIG5fZGlhZyA9IG5fZGlhZykrZ2d0aXRsZSgiQ2xhdWRlMyBIYWlrdSB0MC4xIikKdG9wX2RpYWdub3Npc19wbG90KGRmX2NsYXVkZTNfaGFpa3VfdDEuMCwgbl9kaWFnID0gbl9kaWFnKStnZ3RpdGxlKCJDbGF1ZGUzIEhhaWt1IHQxLjAiKQp0b3BfZGlhZ25vc2lzX3Bsb3QoZGZfY2xhdWRlM19vcHVzX3QxLjAsIG5fZGlhZyA9IG5fZGlhZykrZ2d0aXRsZSgiQ2xhdWRlMyBPcHVzIHQxLjAiKQp0b3BfZGlhZ25vc2lzX3Bsb3QoZGZfZ2VtaW5pMS4wX3Byb190MS4wLCBuX2RpYWcgPSBuX2RpYWcpK2dndGl0bGUoIkdlbWluaSAxLjAgUHJvIikKdG9wX2RpYWdub3Npc19wbG90KGRmX2dlbWluaTEuNV9mbGFzaF90MS4wLCBuX2RpYWcgPSBuX2RpYWcpK2dndGl0bGUoIkdlbWluaSAxLjUgRmxhc2giKQpgYGAKCiMjIyBJQ0QgY29udmVydGVkIHJlc3BvbnNlcyAKCmBgYHtyLCBmaWcud2lkdGggPSAxMiwgZmlnLmhlaWdodCA9IDh9CmN1c3RvbV9sYWJlbGVyIDwtIGZ1bmN0aW9uKHgsIHdyYXBfd2lkdGg9MzMpIHsKICAgIHggJT4lCiAgICAgICAgc3RyX3JlcGxhY2UoIl9fXy4rJCIsICIiKSAlPiUKICAgICAgICBzdHJfd3JhcCh3aWR0aCA9IHdyYXBfd2lkdGgpCn0KCmN1c3RvbV90ZXh0X2Zvcm1hdHRpbmcgPC0gbGlzdCgKICB0aGVtZShheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDcsIGxpbmVoZWlnaHQgPSAwLjcpLCAKICAgICAgICAgIHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDcpLAogICAgICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gOSkpLAogIHRpZHl0ZXh0OjpzY2FsZV94X3Jlb3JkZXJlZChsYWJlbHMgPSB+Y3VzdG9tX2xhYmVsZXIoLiwgd3JhcF93aWR0aCA9IDQ1KSkKKQpgYGAKCgpgYGB7ciwgZmlnLndpZHRoID0gMTYsIGZpZy5oZWlnaHQgPSAxMH0Kbl9kaWFnIDwtIDI1CnRvcF9kaWFnbm9zaXNfcGxvdChkZl9ncHQzLjVfaWNkLCBuX2RpYWcgPSBuX2RpYWcpICsgY3VzdG9tX3RleHRfZm9ybWF0dGluZyArIGdndGl0bGUoIkNoYXRHUFQgMy41IElDRCIpIAp0b3BfZGlhZ25vc2lzX3Bsb3QoZGZfZ3B0NC4wX2ljZCwgbl9kaWFnID0gbl9kaWFnKSsgY3VzdG9tX3RleHRfZm9ybWF0dGluZytnZ3RpdGxlKCJDaGF0R1BUIDQuMCBJQ0QiKQp0b3BfZGlhZ25vc2lzX3Bsb3QoZGZfY2xhdWRlM19oYWlrdV90MS4wX2ljZCwgbl9kaWFnID0gbl9kaWFnKSsgY3VzdG9tX3RleHRfZm9ybWF0dGluZytnZ3RpdGxlKCJDbGF1ZGUzIEhhaWt1IHQxLjAgSUNEIikKdG9wX2RpYWdub3Npc19wbG90KGRmX2NsYXVkZTNfb3B1c190MS4wX2ljZCwgbl9kaWFnID0gbl9kaWFnKSsgY3VzdG9tX3RleHRfZm9ybWF0dGluZytnZ3RpdGxlKCJDbGF1ZGUzIE9wdXMgdDEuMCBJQ0QiKQp0b3BfZGlhZ25vc2lzX3Bsb3QoZGZfZ2VtaW5pMS4wX3Byb190MS4wX2ljZCwgbl9kaWFnID0gbl9kaWFnKSsgY3VzdG9tX3RleHRfZm9ybWF0dGluZytnZ3RpdGxlKCJHZW1pbmkgMS4wIFBybyBJQ0QiKQpgYGAKCiMjIENvbWJpbmVkIG1vZGVsIGRhdGEKCiMjIyBPcmlnaW5hbCByZXNwb25zZXMKCmBgYHtyLCBmaWcud2lkdGggPSAxNiwgZmlnLmhlaWdodCA9IDEwfQptdWx0aV90b3BfZGlhZ25vc2lzX3Bsb3QoZGlzdHJpYnV0aW9uX3ZpcyA9ICJwb2ludHMiLCB3cmFwX3dpZHRoPTQ1LCBuX2RpYWcgPSAyNSwKICAgICAgICAgICAgICAgICAgICAgICAgIGRmX2dwdDMuNSwgZGZfZ3B0NC4wLCBkZl9jbGF1ZGUzX2hhaWt1X3QxLjAsIAogICAgICAgICAgICAgICAgICAgICAgICAgZGZfY2xhdWRlM19vcHVzX3QxLjAsIGRmX2dlbWluaTEuMF9wcm9fdDEuMCkKYGBgCgojIyMgSUNEIGNvbnZlcnRlZCByZXNwb25zZXMKCmBgYHtyLCBmaWcud2lkdGggPSAxNiwgZmlnLmhlaWdodCA9IDEwfQptdWx0aV90b3BfZGlhZ25vc2lzX3Bsb3QoZXJyb3JiYXJfdHlwZSA9ICJyYW5nZSIsIHdyYXBfd2lkdGggPSAzMywgCiAgICAgICAgICAgICAgICAgICAgICAgICBkZl9ncHQzLjVfaWNkLCBkZl9ncHQ0LjBfaWNkLCBkZl9jbGF1ZGUzX2hhaWt1X3QxLjBfaWNkLCAKICAgICAgICAgICAgICAgICAgICAgICAgIGRmX2NsYXVkZTNfb3B1c190MS4wX2ljZCwgZGZfZ2VtaW5pMS4wX3Byb190MS4wX2ljZCkKYGBgCgojIEN1bXVsYXRpdmUgdG9wIGZyZXF1ZW5jeSBwbG90cwoKIyMgSW5kaXZpZHVhbCBtb2RlbCBkYXRhCgojIyMgT3JpZ2luYWwgcmVzcG9uc2VzCgpgYGB7ciwgZmlnLndpZHRoPTMsIGZpZy5oZWlnaHQ9My41fQpjdW11bGF0aXZlX2ZyZXF1ZW5jeV9wbG90KGRmX2dwdDMuNSkkcGxvdCtnZ3RpdGxlKCJHUFQzIikKY3VtdWxhdGl2ZV9mcmVxdWVuY3lfcGxvdChkZl9ncHQ0LjApJHBsb3QrZ2d0aXRsZSgiR1BUNCIpCmN1bXVsYXRpdmVfZnJlcXVlbmN5X3Bsb3QoZGZfY2xhdWRlM19oYWlrdV90MS4wKSRwbG90K2dndGl0bGUoIkNsYXVkZTMgSGFpa3UiKQpjdW11bGF0aXZlX2ZyZXF1ZW5jeV9wbG90KGRmX2NsYXVkZTNfb3B1c190MS4wKSRwbG90K2dndGl0bGUoIkNsYXVkZTMgSGFpa3UiKQpjdW11bGF0aXZlX2ZyZXF1ZW5jeV9wbG90KGRmX2dlbWluaTEuMF9wcm9fdDEuMCkkcGxvdCtnZ3RpdGxlKCJHZW1pbmkgUHJvIDEuMCIpCmBgYApgYGB7cn0KIyBFeGFtcGxlIG9mIGN1bXVsYXRpdmUgZnJlcXVlbmN5IHZhbHVlcwpjdW11bGF0aXZlX2ZyZXF1ZW5jeV9wbG90KGRmX2dwdDQuMCkkZGF0YQpgYGAKCgojIyMgSUNEIGNvbnZlcnRlZCByZXNwb25zZXMKCmBgYHtyLCBmaWcud2lkdGg9MywgZmlnLmhlaWdodD0zLjV9CmN1bXVsYXRpdmVfZnJlcXVlbmN5X3Bsb3QoZGZfZ3B0My41X2ljZCkkcGxvdCtnZ3RpdGxlKCJHUFQzIElDRCIpCmN1bXVsYXRpdmVfZnJlcXVlbmN5X3Bsb3QoZGZfZ3B0NC4wX2ljZCkkcGxvdCtnZ3RpdGxlKCJHUFQ0IElDRCIpCmN1bXVsYXRpdmVfZnJlcXVlbmN5X3Bsb3QoZGZfY2xhdWRlM19oYWlrdV90MS4wX2ljZCkkcGxvdCtnZ3RpdGxlKCJDbGF1ZGUzIEhhaWt1IElDRCIpCmN1bXVsYXRpdmVfZnJlcXVlbmN5X3Bsb3QoZGZfY2xhdWRlM19vcHVzX3QxLjBfaWNkKSRwbG90K2dndGl0bGUoIkNsYXVkZTMgSGFpa3UgSUNEIikKY3VtdWxhdGl2ZV9mcmVxdWVuY3lfcGxvdChkZl9nZW1pbmkxLjBfcHJvX3QxLjBfaWNkKSRwbG90K2dndGl0bGUoIkdlbWluaSBQcm8gMS4wIElDRCIpCmBgYAoKIyMgQ29tYmluZWQgbW9kZWwgZGF0YQoKIyMjIE9yaWdpbmFsIHJlc3BvbnNlcwoKYGBge3IsIGZpZy53aWR0aD0zLCBmaWcuaGVpZ2h0PTMuNX0KbXVsdGlfY3VtdWxhdGl2ZV9mcmVxdWVuY3lfcGxvdCgKICAgIG5fZGlhZ25vc2VzID0gMjUsIGRpc3RyaWJ1dGlvbl92aXMgPSAic3RkX2Vycm9yIiwKICBkZl9ncHQzLjUsIGRmX2dwdDQuMCwgZGZfY2xhdWRlM19oYWlrdV90MS4wLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZl9jbGF1ZGUzX29wdXNfdDEuMCwgZGZfZ2VtaW5pMS4wX3Byb190MS4wKQpgYGAKCiMjIyBJQ0QgY29udmVydGVkIHJlc3BvbnNlcwpgYGB7ciwgZmlnLndpZHRoPTMsIGZpZy5oZWlnaHQ9My41fQptdWx0aV9jdW11bGF0aXZlX2ZyZXF1ZW5jeV9wbG90KAogIG5fZGlhZ25vc2VzID0gMjUsIGRpc3RyaWJ1dGlvbl92aXMgPSAic3RkX2Vycm9yIiwKICBkZl9ncHQzLjVfaWNkLCBkZl9ncHQ0LjBfaWNkLCBkZl9jbGF1ZGUzX2hhaWt1X3QxLjBfaWNkLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICBkZl9jbGF1ZGUzX29wdXNfdDEuMF9pY2QsIGRmX2dlbWluaTEuMF9wcm9fdDEuMF9pY2QpICsKICBnZ3RpdGxlKCJJQ0QgY29udmVydGVkIHJlc3BvbnNlcyIpCmBgYAoKIyBEaWFnbm9zaXMgcmFuayB0YWJsZQoKIyMgSW5kaXZpZHVhbCBtb2RlbCBkYXRhCgojIyMgT3JpZ2luYWwgcmVzcG9uc2VzCmBgYHtyfQpkaWFnbm9zaXNfcmFua190YWJsZShkZl9ncHQzLjUsICJtYXN0IHxtYXN0b2N8YW5hcGh5bGF4aXMiKSAlPiUgbXV0YXRlKGRpYWdub3NpcyA9IHN1YnN0cihkaWFnbm9zaXMsIDEsIDYwKSkKZGlhZ25vc2lzX3JhbmtfdGFibGUoZGZfZ3B0NC4wLCAibWFzdCB8bWFzdG9jfGFuYXBoeWxheGlzIikgJT4lIG11dGF0ZShkaWFnbm9zaXMgPSBzdWJzdHIoZGlhZ25vc2lzLCAxLCA2MCkpIAojIGRpYWdub3Npc19yYW5rX3RhYmxlKGRmX2NsYXVkZTNfaGFpa3VfdDBfMSwgIm1hc3QgfG1hc3RvY3xhbmFwaHlsYXhpcyIpICU+JSBtdXRhdGUoZGlhZ25vc2lzID0gc3Vic3RyKGRpYWdub3NpcywgMSwgNjApKSAKZGlhZ25vc2lzX3JhbmtfdGFibGUoZGZfY2xhdWRlM19oYWlrdV90MS4wLCAibWFzdCB8bWFzdG9jfGFuYXBoeWxheGlzIikgJT4lIG11dGF0ZShkaWFnbm9zaXMgPSBzdWJzdHIoZGlhZ25vc2lzLCAxLCA2MCkpIApkaWFnbm9zaXNfcmFua190YWJsZShkZl9jbGF1ZGUzX29wdXNfdDEuMCwgIm1hc3QgfG1hc3RvY3xhbmFwaHlsYXhpcyIpICU+JSBtdXRhdGUoZGlhZ25vc2lzID0gc3Vic3RyKGRpYWdub3NpcywgMSwgNjApKSAKZGlhZ25vc2lzX3JhbmtfdGFibGUoZGZfZ2VtaW5pMS4wX3Byb190MS4wLCAibWFzdCB8bWFzdG9jfGFuYXBoeWxheGlzIikgJT4lIG11dGF0ZShkaWFnbm9zaXMgPSBzdWJzdHIoZGlhZ25vc2lzLCAxLCA2MCkpIApkaWFnbm9zaXNfcmFua190YWJsZShkZl9nZW1pbmkxLjVfZmxhc2hfdDEuMCwgIm1hc3QgfG1hc3RvY3xhbmFwaHlsYXhpcyIpICU+JSBtdXRhdGUoZGlhZ25vc2lzID0gc3Vic3RyKGRpYWdub3NpcywgMSwgNjApKSAKYGBgCiMjIyBJQ0QgY29udmVydGVkIHJlc3BvbnNlcwpgYGB7cn0KZGlhZ25vc2lzX3JhbmtfdGFibGUoZGZfZ3B0My41X2ljZCwgIm1hc3QgfG1hc3RvY3xhbmFwaHlsYXhpcyIpICU+JSBtdXRhdGUoZGlhZ25vc2lzID0gc3Vic3RyKGRpYWdub3NpcywgMSwgNjApKSAKZGlhZ25vc2lzX3JhbmtfdGFibGUoZGZfZ3B0NC4wX2ljZCwgIm1hc3QgfG1hc3RvY3xhbmFwaHlsYXhpcyIpICU+JSBtdXRhdGUoZGlhZ25vc2lzID0gc3Vic3RyKGRpYWdub3NpcywgMSwgNjApKSAKZGlhZ25vc2lzX3JhbmtfdGFibGUoZGZfY2xhdWRlM19oYWlrdV90MS4wX2ljZCwgIm1hc3QgfG1hc3RvY3xhbmFwaHlsYXhpcyIpICU+JSBtdXRhdGUoZGlhZ25vc2lzID0gc3Vic3RyKGRpYWdub3NpcywgMSwgNjApKSAKZGlhZ25vc2lzX3JhbmtfdGFibGUoZGZfY2xhdWRlM19vcHVzX3QxLjBfaWNkLCAibWFzdCB8bWFzdG9jfGFuYXBoeWxheGlzIikgJT4lIG11dGF0ZShkaWFnbm9zaXMgPSBzdWJzdHIoZGlhZ25vc2lzLCAxLCA2MCkpIApkaWFnbm9zaXNfcmFua190YWJsZShkZl9nZW1pbmkxLjBfcHJvX3QxLjBfaWNkLCAibWFzdCB8bWFzdG9jfGFuYXBoeWxheGlzIikgJT4lIG11dGF0ZShkaWFnbm9zaXMgPSBzdWJzdHIoZGlhZ25vc2lzLCAxLCA2MCkpIApgYGAKCgpgYGB7cn0KbXVsdGlfZGlhZ25vc2lzX3JhbmtfdGFibGUgPC0gZnVuY3Rpb24oc2VhcmNoX3BhdHRlcm4sIC4uLil7CiAgbGlzdE4oLi4uKSAlPiUgCiAgbGFwcGx5KC4sIGRpYWdub3Npc19yYW5rX3RhYmxlLCBwYXR0ZXJuID0gc2VhcmNoX3BhdHRlcm4pICU+JQogIG1hcHBseShmdW5jdGlvbih4LHkpIHttdXRhdGUoeCwgbW9kZWw9eSl9LCAuLCBuYW1lcyguKSwgU0lNUExJRlkgPSBGKSAlPiUgCiAgYmluZF9yb3dzKCkgJT4lIAogIHBpdm90X2xvbmdlcihjb250YWlucyhjKCJtY2FzIiwia2F3YXNha2kiLCJzbGUiLCJtaWdyYWluZSIpKSwgbmFtZXNfdG8gPSAiY3JpdGVyaWEiLCB2YWx1ZXNfdG8gPSAicmFuayIpICU+JSAKICBmaWx0ZXIoZ3JlcGwoIm1jYXMiLCBjcml0ZXJpYSkpICU+JSAKICBmb3JtYXRfbW9kZWxzKCkgJT4lIAogIGZvcm1hdF9jcml0ZXJpYSgpICU+JSAKICBwaXZvdF93aWRlcihuYW1lc19mcm9tID0gIm1vZGVsIiwgdmFsdWVzX2Zyb20gPSAicmFuayIsbmFtZXNfcHJlZml4ID0gIm1vZGVsXyIpICU+JSAKICByb3d3aXNlKCkgJT4lCiAgbXV0YXRlKG1lYW5fcmFuayA9IHJvdW5kKG1lYW4oY19hY3Jvc3MoY29udGFpbnMoIm1vZGVsXyIpKSwgbmEucm09VCkpLCAwKSAlPiUKICBtdXRhdGUocmFua3MgPSBwYXN0ZShjX2Fjcm9zcyhjb250YWlucygibW9kZWxfIikpLCBjb2xsYXBzZSA9ICIsICIpKSAlPiUKICBtdXRhdGUob3V0cHV0ID0gc3RyX2dsdWUoInttZWFuX3Jhbmt9XG5be3JhbmtzfV0iKSkgJT4lCiAgc2VsZWN0KERpYWdub3NpcyA9IGRpYWdub3NpcywgY3JpdGVyaWEsIG91dHB1dCkgJT4lCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9ICJjcml0ZXJpYSIsIHZhbHVlc19mcm9tID0gIm91dHB1dCIpCn0KCnJhbmtfdGFibGUgPC0gbXVsdGlfZGlhZ25vc2lzX3JhbmtfdGFibGUoc2VhcmNoX3BhdHRlcm4gPSAiVDc4XFwuMiB8RDQ3XFwuMDIgfEQ4OVxcLjQxIHxEODlcXC40OSB8RDg5XFwuNCAiLAogICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRmX2dwdDMuNV9pY2QsIGRmX2dwdDQuMF9pY2QsIGRmX2NsYXVkZTNfaGFpa3VfdDEuMF9pY2QsIGRmX2NsYXVkZTNfb3B1c190MS4wX2ljZCwgZGZfZ2VtaW5pMS4wX3Byb190MS4wX2ljZCkKcmFua190YWJsZSAgCmBgYAoKYGBge3J9CnJhbmtfdGFibGUgJT4lIAogIGZsZXh0YWJsZSgpICU+JSAKICB3aWR0aCh3aWR0aCA9IDMwKSAlPiUgCiAgYWxpZ24oaiA9IDI6MywgYWxpZ24gPSAiY2VudGVyIiwgcGFydCA9ICJhbGwiKQogIApgYGAKCgoKCiMgRGl2ZXJzaXR5CgojIyBJbmRpdmlkdWFsIG1vZGVsIGRhdGEKCmBgYHtyfQpjYWxjdWxhdGVfZGl2ZXJzaXR5X2NpIDwtIGZ1bmN0aW9uKGRmLCBiID0gMTAwLCBzZWVkID0gMTIzNCl7CiAgcmVxdWlyZShlbnRyb3BhcnQpCiAgc2V0LnNlZWQoc2VlZCkKICAKICBkZiAlPiUgCiAgY291bnQoY3JpdGVyaWEsIGRpYWdub3Npcywgc29ydCA9IFQpICU+JSAKICBncm91cF9ieShjcml0ZXJpYSkgJT4lIAogIG5lc3QoKSAlPiUgCiAgbXV0YXRlKGJvb3QgPSBtYXAoZGF0YSwgZnVuY3Rpb24oeCl7CiAgICB4IDwtIGRlZnJhbWUoeCkKICAgIHggPC0gZW50cm9wYXJ0OjpFbnRyb3B5Q0koZW50cm9wYXJ0OjpTaGFubm9uLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgU2ltdWxhdGlvbnM9YiwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIE5zID0geCwgcT0xLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgQ29ycmVjdGlvbiA9ICJOb25lIikKICAgIHgKICB9KSkgJT4lIAogIG11dGF0ZShzaGFubm9uID0gbWFwX2RibChkYXRhLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgfmxvZyhlbnRyb3BhcnQ6OkRpdmVyc2l0eShkZWZyYW1lKC4pLCBxPTEsIENvcnJlY3Rpb249Ik5vbmUiKSkpKSAlPiUgIyBDYWxjdWxhdGUgc2hhbm5vbiB3aXRoIGVudHJvcGFydAogIG11dGF0ZShib290ID0gbWFwKGJvb3QsIH5xdWFudGlsZSguLCBjKDAuMDI1LDAuNSwwLjk3NSkpKSkgJT4lIAogIHVubmVzdF93aWRlcihib290KQp9CgpwbG90X2RpdmVyc2l0eV9jaSA8LSBmdW5jdGlvbihkZil7CiAgcGx0IDwtIGRmICU+JSAKICAgIGZvcm1hdF9jcml0ZXJpYSgpICU+JSAKICAgIGdncGxvdChhZXMoeCA9IGNyaXRlcmlhLCB5ID0gc2hhbm5vbikpKwogICAgZ2VvbV9wb2ludChzaXplID0gMSkrCiAgICBnZW9tX2Vycm9yYmFyKGFlcyh5bWluID0gYDIuNSVgLCB5bWF4ID0gYDk3LjUlYCksIHdpZHRoID0gMC4zKSsKICAgIHRoZW1lX2J3KCkgKwogICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkgKwogICAgbGFicyh4ID0gIiIsIHkgPSAiU2hhbm5vbiBkaXZlcnNpdHkiKSAKICByZXR1cm4ocGx0KQp9CmBgYAoKIyMjIE9yaWdpbmFsIHJlc3BvbnNlcwoKYGBge3IsIGZpZy53aWR0aD00LCBmaWcuaGVpZ2h0PTMuNX0KY2FsY3VsYXRlX2RpdmVyc2l0eV9jaShkZl9ncHQzLjUpICU+JSBwbG90X2RpdmVyc2l0eV9jaSgpICsgZ2d0aXRsZSgiR1BUMyIpCmNhbGN1bGF0ZV9kaXZlcnNpdHlfY2koZGZfZ3B0NC4wKSAlPiUgcGxvdF9kaXZlcnNpdHlfY2koKSArIGdndGl0bGUoIkdQVDQiKQpjYWxjdWxhdGVfZGl2ZXJzaXR5X2NpKGRmX2NsYXVkZTNfaGFpa3VfdDEuMCkgJT4lIHBsb3RfZGl2ZXJzaXR5X2NpKCkgKyBnZ3RpdGxlKCJDbGF1ZGUzIEhhaWt1IikKY2FsY3VsYXRlX2RpdmVyc2l0eV9jaShkZl9jbGF1ZGUzX29wdXNfdDEuMCkgJT4lIHBsb3RfZGl2ZXJzaXR5X2NpKCkgKyBnZ3RpdGxlKCJDbGF1ZGUzIE9wdXMiKQpjYWxjdWxhdGVfZGl2ZXJzaXR5X2NpKGRmX2dlbWluaTEuMF9wcm9fdDEuMCkgJT4lIHBsb3RfZGl2ZXJzaXR5X2NpKCkgKyBnZ3RpdGxlKCJHZW1pbmkgdDEuMCIpCgpgYGAKIyMgQ29tYmluZWQgbW9kZWwgZGF0YQoKIyMjIE9yaWdpbmFsIHJlc3BvbnNlcwpgYGB7ciwgZmlnLndpZHRoPTQsIGZpZy5oZWlnaHQ9My41fQpjYWxjdWxhdGVfc2hhbm5vbiA8LSBmdW5jdGlvbihkZil7CiAgdGFibGUoZGYkY3JpdGVyaWEsIGRmJGRpYWdub3NpcykgJT4lIAogICAgdmVnYW46OmRpdmVyc2l0eSgpCn0KCnRpYmJsZShtb2RlbCA9IGMoIkNoYXRHUFQgMy41IiwgIkNoYXRHUFQgNC4wIiwgIkNsYXVkZTMgSGFpa3UiLCAiQ2xhdWRlMyBPcHVzIiwgIkdlbWluaSAxLjAgUHJvIiksCiAgICAgICBkYXRhID0gbGlzdChkZl9ncHQzLjUsIGRmX2dwdDQuMCwgZGZfY2xhdWRlM19oYWlrdV90MS4wLCBkZl9jbGF1ZGUzX29wdXNfdDEuMCwgZGZfZ2VtaW5pMS4wX3Byb190MS4wKSkgJT4lIAogIG11dGF0ZShzaGFubm9uID0gbWFwKGRhdGEsIGNhbGN1bGF0ZV9zaGFubm9uKSkgJT4lIAogIHNlbGVjdChtb2RlbCwgc2hhbm5vbikgJT4lIAogIHVubmVzdF93aWRlcihzaGFubm9uKSAlPiUgCiAgcGl2b3RfbG9uZ2VyKC1tb2RlbCwgbmFtZXNfdG8gPSAiY3JpdGVyaWEiLCB2YWx1ZXNfdG8gPSAic2hhbm5vbiIpICU+JSAKICBmb3JtYXRfY3JpdGVyaWEoKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gY3JpdGVyaWEsIHkgPSBzaGFubm9uLCBjb2xvciA9IG1vZGVsKSkrCiAgc3RhdF9zdW1tYXJ5KGZ1bi5kYXRhID0gbWVhbl9zZSwgZ2VvbSA9ICJlcnJvcmJhciIsIHdpZHRoID0gMC4zLCBhZXMoZ3JvdXAgPSAxKSkrCiAgIyBnZW9tX2JveHBsb3QoYWVzKGdyb3VwID0gY3JpdGVyaWEpKSsKICAjIGdlb21faml0dGVyKHNpemU9IDAuNSkrCiAgZ2VvbV9wb2ludChzaXplID0gMSwgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuNzUpKSsKICB0aGVtZV9idygpICsKICBzY2FsZV9jb2xvcl9icmV3ZXIocGFsZXR0ZSA9ICJEYXJrMiIpKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpICsKICBnZ3B1YnI6Omdlb21fcHdjKGFlcyhncm91cCA9IGNyaXRlcmlhKSwgCiAgICAgICAgICAgICAgICAgICBtZXRob2QgPSAid2lsY294LnRlc3QiLAogICAgICAgICAgICAgICAgICAgbGFiZWwgPSAicC5zaWduaWYiLAogICAgICAgICAgICAgICAgICAgcC5hZGp1c3QubWV0aG9kID0gIkJIIiwKICAgICAgICAgICAgICAgICAgIGhpZGUubnMgPSBULAogICAgICAgICAgICAgICAgICAgdmp1c3QgPSAwLjUKICAgICAgICAgICAgICAgICAgICkrCiAgbGFicyh4ID0gIiIsIHkgPSAiU2hhbm5vbiBEaXZlcnNpdHkiLCBjb2xvciA9ICIiKQogICAgICAgICAgICAgICAgICAgIyByZW1vdmUuYnJhY2tldCA9IFQpCiAgICAgICAgICAgICAgICAgICAjIHN5bW51bS5hcmdzID0gbGlzdChjdXRwb2ludHMgPSBjKDAsIDAuMDAwMSwgMC4wMDEsIDAuMDEsIDAuMDUsIDEpLCAKICAgICAgICAgICAgICAgICAgICMgIHN5bWJvbHMgPSBjKCIqKioqIiwgIioqKiIsICIqKiIsICIqIiwgIm5zIikpKQogICMgZ2dwdWJyOjpzdGF0X2NvbXBhcmVfbWVhbnMoY29tcGFyaXNvbnMgPSBsaXN0KGMoIlNMRSAtIEVVTEFSLUFDUiIsICJNQ0FTIC0gQWx0ZXJuYXRpdmUiKSkpCmBgYAojIyMgSUNEIGNvbnZlcnRlZCByZXNwb25zZXMKYGBge3IsIGZpZy53aWR0aD00LCBmaWcuaGVpZ2h0PTMuNX0KY2FsY3VsYXRlX3NoYW5ub24gPC0gZnVuY3Rpb24oZGYpewogIHRhYmxlKGRmJGNyaXRlcmlhLCBkZiRkaWFnbm9zaXMpICU+JSAKICAgIHZlZ2FuOjpkaXZlcnNpdHkoKQp9Cgp0aWJibGUobW9kZWwgPSBjKCJDaGF0R1BUIDMuNSIsICJDaGF0R1BUIDQuMCIsICJDbGF1ZGUzIEhhaWt1IiwgIkNsYXVkZTMgT3B1cyIsICJHZW1pbmkgMS4wIFBybyIpLAogICAgICAgZGF0YSA9IGxpc3QoZGZfZ3B0My41X2ljZCwgZGZfZ3B0NC4wX2ljZCwgZGZfY2xhdWRlM19oYWlrdV90MS4wX2ljZCwgZGZfY2xhdWRlM19vcHVzX3QxLjBfaWNkLCBkZl9nZW1pbmkxLjBfcHJvX3QxLjBfaWNkKSkgJT4lIAogIG11dGF0ZShzaGFubm9uID0gbWFwKGRhdGEsIGNhbGN1bGF0ZV9zaGFubm9uKSkgJT4lIAogIHNlbGVjdChtb2RlbCwgc2hhbm5vbikgJT4lIAogIHVubmVzdF93aWRlcihzaGFubm9uKSAlPiUgCiAgcGl2b3RfbG9uZ2VyKC1tb2RlbCwgbmFtZXNfdG8gPSAiY3JpdGVyaWEiLCB2YWx1ZXNfdG8gPSAic2hhbm5vbiIpICU+JSAKICBmb3JtYXRfY3JpdGVyaWEoKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gY3JpdGVyaWEsIHkgPSBzaGFubm9uLCBjb2xvciA9IG1vZGVsKSkrCiAgc3RhdF9zdW1tYXJ5KGZ1bi5kYXRhID0gbWVhbl9zZSwgZ2VvbSA9ICJlcnJvcmJhciIsIHdpZHRoID0gMC4zLCBhZXMoZ3JvdXAgPSAxKSkrCiAgIyBnZW9tX2JveHBsb3QoYWVzKGdyb3VwID0gY3JpdGVyaWEpKSsKICAjIGdlb21faml0dGVyKHNpemU9IDAuNSkrCiAgZ2VvbV9wb2ludChzaXplID0gMSwgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuNzUpKSsKICB0aGVtZV9idygpICsKICBzY2FsZV9jb2xvcl9icmV3ZXIocGFsZXR0ZSA9ICJEYXJrMiIpKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpICsKICBnZ3B1YnI6Omdlb21fcHdjKGFlcyhncm91cCA9IGNyaXRlcmlhKSwgCiAgICAgICAgICAgICAgICAgICBtZXRob2QgPSAid2lsY294LnRlc3QiLAogICAgICAgICAgICAgICAgICAgbGFiZWwgPSAicC5zaWduaWYiLAogICAgICAgICAgICAgICAgICAgcC5hZGp1c3QubWV0aG9kID0gIkJIIiwKICAgICAgICAgICAgICAgICAgIGhpZGUubnMgPSBULAogICAgICAgICAgICAgICAgICAgdmp1c3QgPSAwLjUKICAgICAgICAgICAgICAgICAgICkrCiAgbGFicyh4ID0gIiIsIHkgPSAiU2hhbm5vbiBEaXZlcnNpdHkiLCBjb2xvciA9ICIiKQogICAgICAgICAgICAgICAgICAgIyByZW1vdmUuYnJhY2tldCA9IFQpCiAgICAgICAgICAgICAgICAgICAjIHN5bW51bS5hcmdzID0gbGlzdChjdXRwb2ludHMgPSBjKDAsIDAuMDAwMSwgMC4wMDEsIDAuMDEsIDAuMDUsIDEpLCAKICAgICAgICAgICAgICAgICAgICMgIHN5bWJvbHMgPSBjKCIqKioqIiwgIioqKiIsICIqKiIsICIqIiwgIm5zIikpKQogICMgZ2dwdWJyOjpzdGF0X2NvbXBhcmVfbWVhbnMoY29tcGFyaXNvbnMgPSBsaXN0KGMoIlNMRSAtIEVVTEFSLUFDUiIsICJNQ0FTIC0gQWx0ZXJuYXRpdmUiKSkpCmBgYAoKCgoKIyMgUGVybXV0YXRpb24gdGVzdGluZwoKYGBge3IsIGV2YWwgPSBGfQojIFJ1biBvdXRzaWRlIG9mIG5vdGVib29rCiMgSW5jbHVkZXMgYWxsIDEwLDAwMCBHUFQgaXRlcmF0aW9ucyBhbmQgMTAwMCBib290c3RyYXAgcGVybXV0YXRpb25zIAojIENvbnRhaW5lZCBpbiBzY3JpcHQgc291cmNlKGhlcmUoInNjcmlwdHMvZGl2ZXJzaXR5X2FuYWx5c2lzL3Blcm11dGVfbnVsbF9kaXZlcnNpdHlfZGlmZmVyZW5jZS5SIikpCmxpYnJhcnkoaGVyZSkKc291cmNlKGhlcmUoInV0aWxzL2RhdGFfcHJvY2Vzc2luZy5SIikpCmxpYnJhcnkodGlkeXZlcnNlKQpsaWJyYXJ5KHZlZ2FuKQpsaWJyYXJ5KGJyb29tKQpsaWJyYXJ5KGhlcmUpCmxpYnJhcnkoZnVycnIpCmxpYnJhcnkoZnV0dXJlLmFwcGx5KQoKbW9kZWwgPC0gImdwdDQiCnAgPC0gMTAwMAppIDwtIDEwMDAwCgpwcmludCgiIyMjIFJlYWRpbmcgZGF0YSIpCnJlYWRfcGF0aCA8LSBzcHJpbnRmKCJkYXRhL3Byb2Nlc3NlZF9kaWFnbm9zZXMvZGlhZ25vc2VzXyVzLmNzdi5neiIsIG1vZGVsKQpkZiA8LSByZWFkX2NzdihoZXJlKHJlYWRfcGF0aCkpCgpwcmludCgiIyMjIENhbGN1bGF0aW5nIHBlcm11dGF0aW9uIikKcGVybV9vdXQgPC0gZGlmZmVyZW5jZV9wZXJtdXRhdGlvbl90ZXN0KGRmLCBtZXRyaWMgPSAicHJlY2lzaW9uIiwgcGVybXV0YXRpb25zID0gcCwgZ3B0X2l0ZXJhdGlvbnMgPSBpKQoKcHJpbnQoIiMjIyBXcml0aW5nIGRhdGEiKQp3cml0ZV9wYXRoIDwtIHNwcmludGYoImRhdGEvZGl2ZXJzaXR5X2FuYWx5c2lzL3ByZWNpc2lvbl9wZXJtdXRhdGlvbl90ZXN0XyVzX3Alc19pJXMuUkRTIiwgbW9kZWwsIHAsIGkpCnNhdmVSRFMocGVybV9vdXQsIGhlcmUod3JpdGVfcGF0aCkpCmBgYAoKYGBge3J9CmRpdmVyc2l0eV9wZXJtdXRhdGlvbl9yZXN1bHRzIDwtIHJlYWRSRFMoaGVyZSgiZGF0YS9kaXZlcnNpdHlfYW5hbHlzaXMvZGl2ZXJzaXR5X3Blcm11dGF0aW9uX3Rlc3RfZ3B0NC5SRFMiKSkgCmRpdmVyc2l0eV9wZXJtdXRhdGlvbl9yZXN1bHRzCmBgYApgYGB7cn0KcGVybXV0YXRpb25fdGVzdF9wbG90KGRpdmVyc2l0eV9wZXJtdXRhdGlvbl9yZXN1bHRzKQpgYGAKCgojIFNpbWlsYXJpdHkKCiMjIyBKYWNjYXJkL0JyYXkgY3VydGlzCmBgYHtyLCBmaWcud2lkdGg9NC4yNSwgZmlnLmhlaWdodD0zLjV9CmRpYWdub3Npc19zaW1pbGFyaXR5X2hlYXRtYXAoZGZfZ3B0My41LCBtZXRob2QgPSAiYnJheSIpCmRpYWdub3Npc19zaW1pbGFyaXR5X2hlYXRtYXAoZGZfZ3B0NC4wLCBtZXRob2QgPSAiYnJheSIpCmRpYWdub3Npc19zaW1pbGFyaXR5X2hlYXRtYXAoZGZfY2xhdWRlM19oYWlrdV90MS4wLCBtZXRob2QgPSAiYnJheSIpCmRpYWdub3Npc19zaW1pbGFyaXR5X2hlYXRtYXAoZGZfY2xhdWRlM19vcHVzX3QxLjAsIG1ldGhvZCA9ICJicmF5IikKZGlhZ25vc2lzX3NpbWlsYXJpdHlfaGVhdG1hcChkZl9nZW1pbmkxLjBfcHJvX3QxLjAsIG1ldGhvZCA9ICJicmF5IikKYGBgCmBgYHtyLCBmaWcud2lkdGg9NC4yNSwgZmlnLmhlaWdodD0zLjV9CmRpYWdub3Npc19zaW1pbGFyaXR5X2hlYXRtYXAoZGZfZ3B0My41X2ljZCwgbWV0aG9kID0gImJyYXkiKQpkaWFnbm9zaXNfc2ltaWxhcml0eV9oZWF0bWFwKGRmX2dwdDQuMF9pY2QsIG1ldGhvZCA9ICJicmF5IikKZGlhZ25vc2lzX3NpbWlsYXJpdHlfaGVhdG1hcChkZl9jbGF1ZGUzX2hhaWt1X3QxLjBfaWNkLCBtZXRob2QgPSAiYnJheSIpCmRpYWdub3Npc19zaW1pbGFyaXR5X2hlYXRtYXAoZGZfY2xhdWRlM19vcHVzX3QxLjBfaWNkLCBtZXRob2QgPSAiYnJheSIpCmRpYWdub3Npc19zaW1pbGFyaXR5X2hlYXRtYXAoZGZfZ2VtaW5pMS4wX3Byb190MS4wX2ljZCwgbWV0aG9kID0gImJyYXkiKQpgYGAKCi0gQnJheS1DdXJ0aXMgc2ltaWxhcml0eSBtZWFzdXJlcyB0aGUgc2ltaWxhcml0eSBvZiBhIGdpdmVuIGRpYWdub3N0aWMgY3JpdGVyaWHigJlzIHNldCBvZiBhbHRlcm5hdGl2ZSBkaWFnbm9zZXMgYWxvbmcgd2l0aCB0aGVpciBmcmVxdWVuY2llcy4KLSBUaGlzIGRlbW9uc3RyYXRlcyB0aGF0IFNMRSBjcml0ZXJpYSByZXN1bHRzIGluIGEgdmVyeSBzaW1pbGFyIHNldCBhbmQgZnJlcXVlbmN5IG9mIGRpYWdub3Nlcywgd2hpbGUgdGhlIGRpYWdub3NlcyBhc3NvY2lhdGVkIHdpdGggdHdvIE1DQVMgY3JpdGVyaWEgYXJlIGFzIGRpZmZlcmVudCBmcm9tIGVhY2ggb3RoZXIgYXMgdGhleSBhcmUgZnJvbSB0aG9zZSBnZW5lcmF0ZWQgYnkgdGhlIGNyaXRlcmlhIG9mIG90aGVyIGNvbmRpdGlvbnMuCgojIyMgUENBCgpgYGB7ciwgZmlnLndpZHRoPTQuMjUsIGZpZy5oZWlnaHQ9My41fQpkaWFnbm9zaXNfcGNhX3Bsb3QoZGZfZ3B0My41KSArIGdndGl0bGUoIkdQVDMiKQpkaWFnbm9zaXNfcGNhX3Bsb3QoZGZfZ3B0NC4wKSArIGdndGl0bGUoIkdQVDQiKQpkaWFnbm9zaXNfcGNhX3Bsb3QoZGZfY2xhdWRlM19oYWlrdV90MS4wKSArIGdndGl0bGUoIkNsYXVkZSBIYWlrdSIpCmRpYWdub3Npc19wY2FfcGxvdChkZl9jbGF1ZGUzX29wdXNfdDEuMCkgKyBnZ3RpdGxlKCJDbGF1ZGUgT3B1cyIpCmRpYWdub3Npc19wY2FfcGxvdChkZl9nZW1pbmkxLjBfcHJvX3QxLjApICsgZ2d0aXRsZSgiR2VtaW5pIikKYGBgCgpgYGB7cn0KZGlhZ25vc2lzX3BjYV9wbG90IDwtIGZ1bmN0aW9uKGRmKXsKICBkZiA8LSBmb3JtYXRfY3JpdGVyaWEoZGYpCiAgZGlhZ25vc2lzX3RhYmxlIDwtIHRhYmxlKGRmJGNyaXRlcmlhLCBkZiRkaWFnbm9zaXMpCiAgZGlhZ25vc2lzX3BjYSA8LSBhcy5kYXRhLmZyYW1lKGRpYWdub3Npc190YWJsZSkgJT4lIAogICAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9ICJWYXIyIiwgdmFsdWVzX2Zyb20gPSAiRnJlcSIsIHZhbHVlc19maWxsID0gMCkgJT4lIAogICAgY29sdW1uX3RvX3Jvd25hbWVzKCJWYXIxIikgJT4lIAogICAgcHJjb21wKCkKICAKICBhcy5kYXRhLmZyYW1lKGRpYWdub3Npc19wY2EkeCkgJT4lIAogICAgcm93bmFtZXNfdG9fY29sdW1uKCJjcml0ZXJpYSIpICU+JSAKICAgIGdncGxvdChhZXMoeCA9IFBDMSwgeSA9IFBDMiwgbGFiZWwgPSBjcml0ZXJpYSkpKwogICAgZ2VvbV9wb2ludCgpKwogICAgZ2dyZXBlbDo6Z2VvbV9sYWJlbF9yZXBlbCgpICsKICAgIHRoZW1lX2J3KCkKfQoKbXVsdGlfZWRnZV9kZW5zaXR5X3Bsb3QgPC0gZnVuY3Rpb24oLi4uKXsKICBkZl9saXN0IDwtIGxpc3ROKC4uLikKICBkZl9saXN0IDwtIGxhcHBseShkZl9saXN0LCB1bmdyb3VwKQogIAogICMgUHJvY2VzcyBkYXRhCiAgZGZfY29tYmluZWQgPC0gZGZfbGlzdCAlPiUgCiAgICBtYXBwbHkoZnVuY3Rpb24oeCx5KSB7bXV0YXRlKHgsIG1vZGVsPXkpfSwgLiwgbmFtZXMoLiksIFNJTVBMSUZZID0gRikgJT4lIAogICAgYmluZF9yb3dzKCkgJT4lIAogICAgbmVzdCguYnkgPSBjKCJtb2RlbCIsICJjcml0ZXJpYSIpKSAlPiUgCiAgICBtdXRhdGUoZWRnZV9kZW5zaXR5ID0gbWFwX2RibChkYXRhLCB+ZWRnZV9kZW5zaXR5KGdyYXBoX2Zyb21fZGF0YV9mcmFtZSguKSkpKSAlPiUgCiAgICBzZWxlY3QoLWRhdGEpCmBgYAoKYGBge3J9CmRmIDwtIGxpc3ROKGRmX2dwdDMuNV9pY2QsIGRmX2dwdDQuMF9pY2QsIGRmX2NsYXVkZTNfaGFpa3VfdDEuMF9pY2QsIGRmX2NsYXVkZTNfb3B1c190MS4wX2ljZCwgZGZfZ2VtaW5pMS4wX3Byb190MS4wX2ljZCkgJT4lIAogIG1hcHBseShmdW5jdGlvbih4LHkpIHttdXRhdGUoeCwgbW9kZWw9eSl9LCAuLCBuYW1lcyguKSwgU0lNUExJRlkgPSBGKSAlPiUgCiAgYmluZF9yb3dzKCkgJT4lIAogIGNvdW50KG1vZGVsLCBjcml0ZXJpYSwgZGlhZ25vc2lzKSAlPiUgCiAgcGl2b3Rfd2lkZXIobmFtZXNfZnJvbSA9ICJkaWFnbm9zaXMiLCB2YWx1ZXNfZnJvbSA9ICJuIiwgdmFsdWVzX2ZpbGwgPSAwKSAlPiUgCiAgdW5pdGUoaWQsIG1vZGVsLCBjcml0ZXJpYSwgc2VwID0gIl9fIikgJT4lIAogIGNvbHVtbl90b19yb3duYW1lcygiaWQiKSAlPiUgCiAgcHJjb21wKHNjYWxlLiA9IEYpCgphcy5kYXRhLmZyYW1lKGRmJHgpICU+JSAKICAgIHJvd25hbWVzX3RvX2NvbHVtbigiaWQiKSAlPiUgCiAgc2VwYXJhdGUoaWQsIGludG8gPSBjKCJtb2RlbCIsICJjcml0ZXJpYSIpLCBzZXAgPSAiX18iKSAlPiUgCiAgZm9ybWF0X2NyaXRlcmlhKCkgJT4lIAogIGZvcm1hdF9tb2RlbHMoKSAlPiUgCiAgZ2dwbG90KGFlcyh4ID0gUEMxLCB5ID0gUEMyLCBjb2xvciA9IGNyaXRlcmlhKSkrCiAgICBnZW9tX3BvaW50KCkrCiAgICAjIGdncmVwZWw6Omdlb21fbGFiZWxfcmVwZWwoKSArCiAgICB0aGVtZV9idygpICsKICBzY2FsZV9jb2xvcl9icmV3ZXIocGFsZXR0ZSA9ICJEYXJrMiIpCmBgYAoKIyBQcmVjaXNpb24KCi0gUHJlY2lzaW9uIHJlcHJlc2VudHMgaG93IHNpbWlsYXIgZWFjaCBpdGVyYXRpb24gb2YgYSAxMC1wb2ludCBkaWZmZXJlbnRpYWwgZGlhZ25vc2lzIGlzIHdpdGggYWxsIG90aGVyIGRpZmZlcmVudGlhbCBkaWFnbm9zZXMgZnJvbSB0aGUgc2FtZSBzZXQgb2YgY3JpdGVyaWEuIAotIEkuZS4gaG93IHJlcHJvZHVjaWJsZSB0aGUgMTAtcG9pbnQgZGlmZmVyZW50aWFsIGRpYWdub3NpcyBpcyBmb3IgZWFjaCBjcml0ZXJpYQotIE1lYXN1cmVkIGJ5IG9idGFpbmluZyB0aGUgQnJheS1DdXJ0aXMgc2ltaWxhcml0eSB2YWx1ZXMgYmV0d2VlbiBhbGwgaXRlcmF0aW9ucyB3aXRoaW4gYSBjcml0ZXJpYQoKYGBge3IsIGV2YWw9Rn0KIyBTY3JpcHQgZm9yIGNhbGN1bGF0aW5nIGFsbCBCcmF5LUN1cnRpcyBzaW1pbGFyaXR5IHZhbHVlcyB3aXRoaW4gYSBjcml0ZXJpYQojIEZvdW5kIGluIHNvdXJjZShoZXJlKCJzY3JpcHRzL2RpdmVyc2l0eV9hbmFseXNpcy9jYWxjdWxhdGVfcHJlY2lzaW9uLlIiKSkKbGlicmFyeShoZXJlKQpzb3VyY2UoaGVyZSgidXRpbHMvZGF0YV9wcm9jZXNzaW5nLlIiKSkKCm1vZGVscyA8LSBjKCJncHQzIiwgImdwdDQiLCAiZ3B0NF9pY2QiKQoKZm9yIChtIGluIG1vZGVscyl7CiAgcHJpbnQoc3ByaW50ZigiUkVBRElORyBJTiBEQVRBIEZPUjogJXMiLCBtKSkKICByZWFkX3BhdGggPC0gc3ByaW50ZigiZGF0YS9wcm9jZXNzZWRfZGlhZ25vc2VzL2RpYWdub3Nlc18lcy5jc3YuZ3oiLCBtKQogIGRmIDwtIHJlYWRfY3N2KGhlcmUocmVhZF9wYXRoKSkKICAKICBwcmludChzcHJpbnRmKCJDQUxDVUxBVElORyBQUkVDSVNJT04gRk9SOiAlcyIsIG0pKQogIGRmIDwtIGNhbGN1bGF0ZV9wcmVjaXNpb24oZGYpCiAgCiAgcHJpbnQoc3ByaW50ZigiV1JJVElORyBQUkVDSVNJT04gREFUQSBGT1I6ICVzIiwgbSkpCiAgb3V0X3BhdGggPC0gc3ByaW50ZigiZGF0YS9kaXZlcnNpdHlfYW5hbHlzaXMvZGlhZ25vc2lzX3ByZWNpc2lvbl8lcy5jc3YuZ3oiLCBtKQogIHdyaXRlX2NzdihkZiwgaGVyZShvdXRfcGF0aCkpCn0KYGBgCgpgYGB7cn0Kc3VtbWFyaXNlX3ByZWNpc2lvbiA8LSBmdW5jdGlvbihwYXRoKXsKICBkZiA8LSB2cm9vbTo6dnJvb20oaGVyZShwYXRoKSkKICBkZiAlPiUgCiAgICBtdXRhdGUoZGlzdGFuY2UgPSAxLWRpc3RhbmNlKSAlPiUgIyBDb252ZXJ0IHRvIHNpbWlsYXJpdHkKICAgIHN1bW1hcmlzZShtZWFuX2NsX25vcm1hbChkaXN0YW5jZSksIC5ieSA9IGNyaXRlcmlhKQp9CgoKCmRmX3ByZWNpc2lvbiA8LSBkYXRhLmZyYW1lKG1vZGVsID0gYygiZ3B0My41IiwgImdwdDQuMCIsICJjbGF1ZGUzX2hhaWt1X3QxLjAiLCAiY2xhdWRlM19vcHVzX3QxLjAiLCAiZ2VtaW5pMS4wX3Byb190MS4wIikpICU+JSAKICBtdXRhdGUocGF0aCA9IG1hcF9jaHIobW9kZWwsIH5zdHJfZ2x1ZSgiZGF0YS9kaXZlcnNpdHlfYW5hbHlzaXMvZGlhZ25vc2lzX3ByZWNpc2lvbl97Ln1faWNkLmNzdi5neiIpKSkgJT4lIG11dGF0ZShkYXRhID0gbWFwKHBhdGgsIHN1bW1hcmlzZV9wcmVjaXNpb24pKSAlPiUgCiAgc2VsZWN0KC1wYXRoKSAlPiUgCiAgdW5uZXN0KGRhdGEpCgoKYGBgCgpgYGB7ciwgZmlnLndpZHRoPTQsIGZpZy5oZWlnaHQ9My41fQpkZl9wcmVjaXNpb24gJT4lIAogIGZvcm1hdF9jcml0ZXJpYSgpICU+JSAKICBmb3JtYXRfbW9kZWxzKCkgJT4lCiAgZ2dwbG90KGFlcyh4ID0gY3JpdGVyaWEsIHkgPSB5KSkrCiAgZ2VvbV9wb2ludChhZXMoY29sb3IgPSBtb2RlbCksIHBvc2l0aW9uID0gcG9zaXRpb25fZG9kZ2Uod2lkdGggPSAwLjc1KSkrCiAgdGhlbWVfYncoKSsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZT0gNDUsIGhqdXN0ID0gMSkpKwogIGxhYnMoeD0iIiwgeSA9ICJBdmVyYWdlIEJyYXktQ3VydGlzIFNpbWlsYXJpdHkiKSArCiAgZ2dwdWJyOjpnZW9tX3B3YyhtZXRob2QgPSAid2lsY294LnRlc3QiLCBwLmFkanVzdC5tZXRob2QgPSAiQkgiLCBoaWRlLm5zID0gVCwgbGFiZWwgPSAicC5hZGouc2lnbmlmIiwgYnJhY2tldC5udWRnZS55ID0gMC4zLCB2anVzdCA9IDAuNiwgc3RlcC5pbmNyZWFzZSA9IDAuMTQsIHRpcC5sZW5ndGggPSAwLjAyKSArCiAgeWxpbShjKDAsMSkpICsKICBsYWJzKGNvbG9yPU5VTEwpKwogIHNjYWxlX2NvbG9yX2JyZXdlcihwYWxldHRlID0gIkRhcmsyIikKYGBgCgpgYGB7cn0KZGZfcHJlY2lzaW9uIDwtIHZyb29tOjp2cm9vbShoZXJlKCJkYXRhL2RpdmVyc2l0eV9hbmFseXNpcy9kaWFnbm9zaXNfcHJlY2lzaW9uX2dwdDQuY3N2Lmd6IikpCmBgYAoKYGBge3J9CmRmX3ByZWNpc2lvbl9zdW1tYXJ5IDwtIGRmX3ByZWNpc2lvbiAlPiUgCiAgbXV0YXRlKGRpc3RhbmNlID0gMS1kaXN0YW5jZSkgJT4lICMgQ29udmVydCB0byBzaW1pbGFyaXR5CiAgc3VtbWFyaXNlKG1lYW5fY2xfbm9ybWFsKGRpc3RhbmNlKSwgLmJ5ID0gY3JpdGVyaWEpCmRmX3ByZWNpc2lvbl9zdW1tYXJ5CmBgYAoKYGBge3IsIGZpZy53aWR0aCA9IDMsIGZpZy5oZWlnaHQgPSAzfQpjYWxjdWxhdGVfYm94cGxvdF9zdGF0cyA8LSBmdW5jdGlvbihkZil7CiAgZGYgJT4lIAogICAgbmVzdChkYXRhID0gZGlzdGFuY2UsIC5ieSA9IGNyaXRlcmlhKSAlPiUgCiAgICBtdXRhdGUoYm94ID0gbWFwKGRhdGEsIGZ1bmN0aW9uKGRmKXsKICAgICAgeCA8LSBib3hwbG90LnN0YXRzKGRmJGRpc3RhbmNlKSRzdGF0cwogICAgICB4IDwtIHNvcnQoeCkKICAgICAgbmFtZXMoeCkgPC0gYygibWluIiwibG93ZXIiLCJtZWRpYW4iLCJ1cHBlciIsIm1heCIpCiAgICAgIHJldHVybih4KQogICAgfSkpICU+JSAKICAgIHNlbGVjdCgtZGF0YSkgJT4lIAogICAgdW5uZXN0X3dpZGVyKGJveCkKfQoKCgptYW51YWxfYm94X3Bsb3QgPC0gZnVuY3Rpb24oZGYsIHdpZHRoID0gMC45KXsKICBkZiAlPiUgCiAgICBmb3JtYXRfY3JpdGVyaWEoKSAlPiUgCiAgICBnZ3Bsb3QoYWVzKAogICAgICB4ID0gY3JpdGVyaWEsCiAgICAgIHltaW4gPSBtaW4sCiAgICAgIGxvd2VyID0gbG93ZXIsCiAgICAgIG1pZGRsZSA9IG1lZGlhbiwKICAgICAgdXBwZXIgPSB1cHBlciwKICAgICAgeW1heCA9IG1heAogICAgKSkrCiAgICBnZW9tX2JveHBsb3Qoc3RhdCA9ICJpZGVudGl0eSIsIHdpZHRoID0gd2lkdGgpICsKICAgIHRoZW1lX2J3KCkgKwogICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA0NSwgaGp1c3QgPSAxKSkrCiAgICBsYWJzKHggPSAiIiwgeSA9ICJCcmF5LUN1cnRpcyBzaW1pbGFyaXR5IikKfQoKYGBgCgoKYGBge3J9CmRmX3ByZWNpc2lvbl9zdGF0cyA8LSBkZl9wcmVjaXNpb24gJT4lIAogIG11dGF0ZShkaXN0YW5jZSA9IDEtZGlzdGFuY2UpICU+JSAjIENvbnZlcnQgdG8gc2ltaWxhcml0eQogIGNhbGN1bGF0ZV9ib3hwbG90X3N0YXRzKCkKZGZfcHJlY2lzaW9uX3N0YXRzCmBgYApgYGB7ciwgZmlnLndpZHRoPTMsIGZpZy5oZWlnaHQ9M30KbWFudWFsX2JveF9wbG90KGRmX3ByZWNpc2lvbl9zdGF0cykKYGBgCiMjIyBQZXJtdXRhdGlvbiB0ZXN0aW5nCgpgYGB7ciwgZXZhbCA9IEZ9CiMgUnVuIG91dHNpZGUgb2Ygbm90ZWJvb2sKIyBUcmllZCBtdWx0aXBsZSBjb21iaW5hdGlvbnMgb2YgYm9vdHN0cmFwIHBlcm11dGF0aW9ucyBhbmQgZ3B0X2l0ZXJhdGlvbnMKIyBCZWNhdXNlIGEgc2luZ2xlIGJyYXktY3VydGlzIG1hdHJpeCBvZiBhbGwgMTAsMDAwIGNvbXBhcmlzb25zIHRha2VzIH4xMCBtaW51dGVzCiMgQ29udGFpbmVkIGluIGZvbGxvd2luZyBzY3JpcHQ6CiMgc291cmNlKGhlcmUoInNjcmlwdHMvZGl2ZXJzaXR5X2FuYWx5c2lzL3Blcm11dGVfbnVsbF9wcmVjaXNpb25fZGlmZmVyZW5jZS5SIikpCm1vZGVsIDwtICJncHQ0IgpwIDwtIDEwMDAKaSA8LSAxMDAwMAoKcHJpbnQoIiMjIyBSZWFkaW5nIGRhdGEiKQpyZWFkX3BhdGggPC0gc3ByaW50ZigiZGF0YS9wcm9jZXNzZWRfZGlhZ25vc2VzL2RpYWdub3Nlc18lcy5jc3YuZ3oiLCBtb2RlbCkKZGYgPC0gcmVhZF9jc3YoaGVyZShyZWFkX3BhdGgpKQoKcHJpbnQoIiMjIyBDYWxjdWxhdGluZyBwZXJtdXRhdGlvbiIpCnBlcm1fb3V0IDwtIGRpZmZlcmVuY2VfcGVybXV0YXRpb25fdGVzdChkZiwgbWV0cmljID0gInByZWNpc2lvbiIsIHBlcm11dGF0aW9ucyA9IHAsIGdwdF9pdGVyYXRpb25zID0gaSkKCnByaW50KCIjIyMgV3JpdGluZyBkYXRhIikKd3JpdGVfcGF0aCA8LSBzcHJpbnRmKCJkYXRhL2RpdmVyc2l0eV9hbmFseXNpcy9wcmVjaXNpb25fcGVybXV0YXRpb25fdGVzdF8lc19wJXNfaSVzLlJEUyIsIG1vZGVsLCBwLCBpKQpzYXZlUkRTKHBlcm1fb3V0LCBoZXJlKCkpCmBgYAoKCmBgYHtyfQpyZWFkUkRTKGhlcmUoImRhdGEvZGl2ZXJzaXR5X2FuYWx5c2lzL3ByZWNpc2lvbl9wZXJtdXRhdGlvbl90ZXN0X2dwdDRfcDEwMDBfaTEwMDAwLlJEUyIpKQpgYGAKCgpgYGB7cn0KcmVhZFJEUyhoZXJlKCJkYXRhL2RpdmVyc2l0eV9hbmFseXNpcy9wcmVjaXNpb25fcGVybXV0YXRpb25fdGVzdF9ncHQ0X3AxMDAwX2kxMDAwMC5SRFMiKSkgJT4lIHBlcm11dGF0aW9uX3Rlc3RfcGxvdCgpCmBgYAoKCiMgaU5FWFQKCmBgYHtyLCBmaWcud2lkdGg9MTIsIGZpZy5oZWlnaHQ9NH0KaW5leHRfcGxvdHMgPC0gZnVuY3Rpb24oaW5leHRfb2JqKXsKICBmb3IgKGkgaW4gMTozKXsKICAgIHBsdCA8LSBpTkVYVDo6Z2dpTkVYVChpbmV4dF9vYmosIHR5cGU9aSwgZmFjZXQudmFyPSJBc3NlbWJsYWdlIiwgY29sb3IudmFyPSJBc3NlbWJsYWdlIikgKwogICAgICB0aGVtZV9jbGFzc2ljKCkgKyAKICAgICAgc2NhbGVfY29sb3JfYnJld2VyKHBhbGV0dGUgPSAiU2V0MSIpICsKICAgICAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGUgPSA5MCkpKwogICAgICBzY2FsZV9jb2xvcl9icmV3ZXIocGFsZXR0ZSA9ICJEYXJrMiIpCiAgICBwcmludChwbHQpCiAgfQp9CgpyZWFkUkRTKGhlcmUoImRhdGEvZGl2ZXJzaXR5X2FuYWx5c2lzL21jYXNfaU5FWFRfZ3B0NF9lMjUwMDAwLlJEUyIpKSAlPiUgaW5leHRfcGxvdHMoKQpyZWFkUkRTKGhlcmUoImRhdGEvZGl2ZXJzaXR5X2FuYWx5c2lzL21jYXNfaU5FWFRfZHJvcFNpbmdsZV9ncHQ0X2UyMDAwMDAuUkRTIikpICU+JSBpbmV4dF9wbG90cygpCnJlYWRSRFMoaGVyZSgiZGF0YS9kaXZlcnNpdHlfYW5hbHlzaXMvbWNhc19pTkVYVF9kcm9wU2luZ2xlX3BzdWVkb01pbnVzX2dwdDRfZTIwMDAwMC5SRFMiKSkgJT4lIGluZXh0X3Bsb3RzKCkKYGBgCgoKIyBGaW5hbCBmaWd1cmVzCgojIyMgMl9Ub3BfZGlhZ25vc2VzCmBgYHtyLCBmaWcud2lkdGg9Ny40LCBmaWcuaGVpZ2h0PTYuNX0KY3VzdG9tX2xhYmVsZXIgPC0gZnVuY3Rpb24oeCwgd3JhcF93aWR0aD0zMykgewogICAgeCAlPiUKICAgICAgICBzdHJfcmVwbGFjZSgiX19fLiskIiwgIiIpICU+JQogICAgICAgIHN0cl93cmFwKHdpZHRoID0gd3JhcF93aWR0aCkKfQoKcGx0X3RvcCA8LSB0b3BfZGlhZ25vc2lzX3Bsb3QoZGZfZ3B0NCwgbl9kaWFnID0gMjUpICsgCiAgdGhlbWUoYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSA1LCBsaW5laGVpZ2h0ID0gMC43KSwgCiAgICAgICAgc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gNyksCiAgICAgICAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gOSkpICsgCiAgdGlkeXRleHQ6OnNjYWxlX3hfcmVvcmRlcmVkKGxhYmVscyA9IGN1c3RvbV9sYWJlbGVyKQpwbHRfdG9wCmBgYAoKYGBge3J9Cmdnc2F2ZShwbG90PXBsdF90b3AsZmlsZW5hbWU9aGVyZSgiZmlndXJlcy8zX1RvcF8yNV9kaWFnbm9zZXMucGRmIiksIHdpZHRoID0gNy40LCBoZWlnaHQgPSA2LjUpCmBgYAoKCiMjIyAzQV9SYW5rX2FidW5kYW5jZQpgYGB7ciwgZmlnLndpZHRoPTMuNSwgZmlnLmhlaWdodD0yLjV9CnBsdF9yYW5rIDwtIHJhbmtfYWJ1bmRhbmNlX3Bsb3QoZGZfZ3B0NCkgK3RoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9IGMoMC43LDAuNykpCnBsdF9yYW5rCmBgYAoKIyMjIDNCX0N1bXVsYXRpdmVfZnJlcXVlbmN5CgpgYGB7ciwgZmlnLndpZHRoPTIuNSwgZmlnLmhlaWdodD0yLjV9CnBsdF9jdW11bGF0aXZlIDwtIGN1bXVsYXRpdmVfZnJlcXVlbmN5X3Bsb3QoZGZfZ3B0NCkgKwogIGxhYnMoeSA9ICJDb21iaW5lZCBmcmVxdWVuY3lcbm9mIHRvcCAyNSBkaWFnbm9zZXMiKQpwbHRfY3VtdWxhdGl2ZQpgYGAKCgoKIyMjIDNDX0RpdmVyc2l0eQpgYGB7ciwgZmlnLndpZHRoPTMsIGZpZy5oZWlnaHQ9M30KcGx0X2RpdiA8LSBkZl9kaXZlcnNpdHlfY2kgJT4lIAogIGZvcm1hdF9jcml0ZXJpYSgpICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBjcml0ZXJpYSwgeSA9IHNoYW5ub24pKSsKICBnZW9tX3BvaW50KHNpemUgPSAxKSsKICBnZW9tX2Vycm9yYmFyKGFlcyh5bWluID0gYDIuNSVgLCB5bWF4ID0gYDk3LjUlYCksIHdpZHRoID0gMC4zKSsKICB0aGVtZV9idygpICsKICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKSArCiAgbGFicyh4ID0gIiIsIHkgPSAiU2hhbm5vbiBkaXZlcnNpdHkiKSAKcGx0X2RpdgpgYGAKIyMjIDNEX1ByZWNpc2lvbgpgYGB7ciwgZmlnLndpZHRoPTMsIGZpZy5oZWlnaHQ9M30KcGx0X3ByZWNpc2lvbiA8LSBtYW51YWxfYm94X3Bsb3QoZGZfcHJlY2lzaW9uX3N0YXRzKQpwbHRfcHJlY2lzaW9uCmBgYAojIyMgM19Db21waWxlZCAKCmBgYHtyLCBmaWcud2lkdGg9Ni41LCBmaWcuaGVpZ2h0PTZ9CnBsdF9maWczIDwtIHBsb3RfZ3JpZCgKICBwbG90X2dyaWQoTlVMTCksCiAgcGxvdF9ncmlkKAogICAgcGx0X3JhbmssCiAgICBOVUxMLAogICAgcGx0X2N1bXVsYXRpdmUsCiAgICBucm93ID0gMSwgCiAgICByZWxfd2lkdGhzID0gYygzLDAuMiwyKSwKICAgIGxhYmVscyA9IGMoIkEiLCAiIiwgIkIiKSwKICAgIHZqdXN0ID0gMC4yCiAgKSwKICBwbG90X2dyaWQoTlVMTCksCiAgcGxvdF9ncmlkKAogICAgcGx0X2RpdiwKICAgIE5VTEwsCiAgICBwbHRfcHJlY2lzaW9uLAogICAgbnJvdyA9IDEsCiAgICByZWxfd2lkdGhzID0gYygxLDAuMSwxKSwKICAgIGxhYmVscyA9IGMoIkMiLCAiIiwgIkQiKSwKICAgIHZqdXN0ID0gMC4yCiAgKSwKICBuY29sID0gMSwKICByZWxfaGVpZ2h0cyA9IGMoMC4wNSwxLDAuMDUsMSkKKQpwbHRfZmlnMwpnZ3NhdmUocGxvdD1wbHRfZmlnMyxmaWxlbmFtZT1oZXJlKCJmaWd1cmVzLzRfRGlhZ25vc2lzX2RpdmVyc2l0eS5wZGYiKSwgd2lkdGggPSA2LjUsIGhlaWdodCA9IDYpCmBgYAoKIyMjIFRhYmxlCgpgYGB7ciwgbWVzc2FnZSA9IEYsIHdhcm5pbmc9RkFMU0V9CmRpYWdub3Npc19yYW5rX3RhYmxlKGRmX2dwdDQsICJtYXN0IHxtYXN0b2N8YW5hcGh5bGF4aXMiKSAlPiUgbXV0YXRlKGRpYWdub3NpcyA9IHN1YnN0cihkaWFnbm9zaXMsIDEsIDYwKSkgJT4lIAogIHNlbGVjdChjb250YWlucyhjKCJkaWFnbm9zaXMiLCJtY2FzIikpKSAlPiUgCiAgaGVhZCg2KSAlPiUgCiAgbXV0YXRlKGRpYWdub3NpcyA9IHN0cl90b19zZW50ZW5jZShkaWFnbm9zaXMpKSAlPiUgCiAgcmVuYW1lKERpYWdub3NpcyA9IGRpYWdub3NpcywgYE1DQVMgY29uc29ydGl1bWAgPSBtY2FzX2NvbnNvcnRpdW0sIGBNQ0FTIGFsdGVybmF0aXZlYCA9IG1jYXNfYWx0ZXJuYXRpdmUpICU+JSAKICBmbGV4dGFibGUoKSAlPiUgCiAgd2lkdGgod2lkdGggPSAyKSAlPiUgCiAgYWxpZ24oaiA9IDI6MywgYWxpZ24gPSAiY2VudGVyIiwgcGFydCA9ICJhbGwiKSAlPiUgCiAge3ByaW50KC4sIHByZXZpZXcgPSAicGRmIik7Ln0KYGBgCgojIyMgU3VwcGxlbWVudGFsIGZpZ3VyZXMKCmBgYHtyLCBmaWcud2lkdGg9NywgZmlnLmhlaWdodD0xMCwgbWVzc2FnZSA9IEZ9CnBsb3RfZ3JpZCgKICB0b3BfZGlhZ25vc2lzX3Bsb3QoZGZfZ3B0Mywgbl9kaWFnID0gMjUpICsgCiAgICB0aGVtZShheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDQuNSwgbGluZWhlaWdodCA9IDAuNyksIAogICAgICAgICAgc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gNyksCiAgICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSA5KSkgKyAKICAgIHRpZHl0ZXh0OjpzY2FsZV94X3Jlb3JkZXJlZChsYWJlbHMgPSBjdXN0b21fbGFiZWxlciksCiAgCiAgdG9wX2RpYWdub3Npc19wbG90KGRmX2dwdDRfaWNkLCBuX2RpYWcgPSAyNSkgKyAKICAgIHRoZW1lKGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gNCwgbGluZWhlaWdodCA9IDAuNyksIAogICAgICAgICAgc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gNyksCiAgICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSA5KSkgKyAKICAgIHRpZHl0ZXh0OjpzY2FsZV94X3Jlb3JkZXJlZChsYWJlbHMgPSB+Y3VzdG9tX2xhYmVsZXIoLiwgd3JhcF93aWR0aCA9IDQ1KSksCiAgbmNvbCA9IDEsCiAgcmVsX2hlaWdodHMgPSBjKDAuOSwxKSwKICBsYWJlbHMgPSBjKCJBIiwiQiIpCikgJT4lIAogIHtnZ3NhdmUocGxvdD0uLGZpbGVuYW1lPWhlcmUoImZpZ3VyZXMvU19Ub3BfZGlhZ25vc2VzLnBkZiIpLCB3aWR0aCA9IDcsIGhlaWdodCA9IDEwKTsufQpgYGAKYGBge3IsIGZpZy53aWR0aD03LjUsIGZpZy5oZWlnaHQ9M30KcGxvdF9ncmlkKAogIHJhbmtfYWJ1bmRhbmNlX3Bsb3QoZGZfZ3B0MykgK3RoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9IGMoMC43LDAuNykpLAogIHJhbmtfYWJ1bmRhbmNlX3Bsb3QoZGZfZ3B0NF9pY2QpICt0aGVtZShsZWdlbmQucG9zaXRpb24gPSBjKDAuNywwLjcpKSwKICBucm93ID0gMSwKICBsYWJlbHMgPSBjKCJBIiwiQiIpCikgJT4lIAogIHtnZ3NhdmUocGxvdD0uLGZpbGVuYW1lPWhlcmUoImZpZ3VyZXMvU19SYW5rZWRfYWJ1bmRhbmNlLnBkZiIpLCB3aWR0aCA9IDcuNSwgaGVpZ2h0ID0gMyk7Ln0KYGBgCgojIEFsdGVybmF0aXZlIGNvbWJpbmVkIGZpZ3VyZQpgYGB7ciwgZmlnLndpZHRoPTcsIGZpZy5oZWlnaHQ9OSwgbWVzc2FnZSA9IEZ9Cm5fZGlhZ25vc2VzX2JhciA8LSAxNQpuX2RpYWdub3Nlc19hYnVuZGFuY2UgPC0gNTAKbl9kaWFnbm9zZXNfY3VtdWxhdGl2ZSA8LSA1MAoKYXBwbHlfdGV4dF9mb3JtYXR0aW5nIDwtIGxpc3QodGhlbWUoCiAgYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSA2KSwKICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSA5KSwKICBsZWdlbmQudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gNiksCiAgIyBsZWdlbmQuc3BhY2luZy55ID0gdW5pdCgwLjEsICdjbScpCiAgIyBsZWdlbmQuaGVpZ2h0ID0gdW5pdCgwLjEsICdjbScpLAogIGxlZ2VuZC5rZXkuaGVpZ2h0ID0gdW5pdCgwLjMsICdjbScpCiAgIyBsZWdlbmQua2V5LnNwYWNpbmcgPSB1bml0KDAuMSwgJ2NtJykKICApKQogIAogIApwbG90X2dyaWQoCiAgCiAgIyMjCiAgdG9wX2RpYWdub3Npc19wbG90KGRmX2dwdDQsIG5fZGlhZyA9IG5fZGlhZ25vc2VzX2JhcikgKyAKICAgIHRoZW1lKGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gNSwgbGluZWhlaWdodCA9IDAuNyksIAogICAgICAgICAgc3RyaXAudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gNyksCiAgICAgICAgICBheGlzLnRpdGxlID0gZWxlbWVudF90ZXh0KHNpemUgPSA5KSkgKyAKICAgIHRpZHl0ZXh0OjpzY2FsZV94X3Jlb3JkZXJlZChsYWJlbHMgPSBjdXN0b21fbGFiZWxlciksCiAgIyMjCiAgTlVMTCwKICBwbG90X2dyaWQoCiAgICBwbG90X2dyaWQoTlVMTCksCiAgICBwbG90X2dyaWQoCiAgICAgIE5VTEwsCiAgICAgICMjIyMKICAgICAgcmFua19hYnVuZGFuY2VfcGxvdChkZl9ncHQ0LCBuX2RpYWdub3NlcyA9IG5fZGlhZ25vc2VzX2FidW5kYW5jZSkgK3RoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9IGMoMC43LDAuNykpICsgYXBwbHlfdGV4dF9mb3JtYXR0aW5nLAogICAgICAjIyMKICAgICAgTlVMTCwKICAgICAgIyMjCiAgICAgIGN1bXVsYXRpdmVfZnJlcXVlbmN5X3Bsb3QoZGZfZ3B0NCwgbl9kaWFnbm9zZXMgPSBuX2RpYWdub3Nlc19jdW11bGF0aXZlKSArIGxhYnMoeSA9IHN0cl9nbHVlKCJDb21iaW5lZCBmcmVxdWVuY3lcbm9mIHRvcCB7bl9kaWFnbm9zZXNfY3VtdWxhdGl2ZX0gZGlhZ25vc2VzIikpICsgYXBwbHlfdGV4dF9mb3JtYXR0aW5nLAogICAgICAjIyMKICAgICAgTlVMTCwKICAgICAgbnJvdyA9IDEsIAogICAgICByZWxfd2lkdGhzID0gYygwLjIsIDIuNSwgMC4yLCAyLCAwLjIgKSwKICAgICAgIyBsYWJlbHMgPSBjKCJBIiwgIiIsICJCIiksCiAgICAgIHZqdXN0ID0gMC4yCiAgICApLAogICAgcGxvdF9ncmlkKE5VTEwpLAogICAgcGxvdF9ncmlkKAogICAgICBOVUxMLAogICAgICAjIyMKICAgICAgIGRmX2RpdmVyc2l0eV9jaSAlPiUgCiAgICAgICAgZm9ybWF0X2NyaXRlcmlhKCkgJT4lIAogICAgICAgIGdncGxvdChhZXMoeCA9IGNyaXRlcmlhLCB5ID0gc2hhbm5vbikpKwogICAgICAgIGdlb21fcG9pbnQoc2l6ZSA9IDEpKwogICAgICAgIGdlb21fZXJyb3JiYXIoYWVzKHltaW4gPSBgMi41JWAsIHltYXggPSBgOTcuNSVgKSwgd2lkdGggPSAwLjMpKwogICAgICAgIHRoZW1lX2J3KCkgKwogICAgICAgIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpICsKICAgICAgICBsYWJzKHggPSAiIiwgeSA9ICJTaGFubm9uXG5kaXZlcnNpdHkiKSArIGFwcGx5X3RleHRfZm9ybWF0dGluZywKICAgICAgIyMjCiAgICAgIE5VTEwsCiAgICAgICMjIwogICAgICBtYW51YWxfYm94X3Bsb3QoZGZfcHJlY2lzaW9uX3N0YXRzKSArIGxhYnMoeT0nQnJheS1DdXJ0aXNcbnNpbWlsYXJpdHknKSArIGFwcGx5X3RleHRfZm9ybWF0dGluZywKICAgICAgIyMjCiAgICAgIE5VTEwsCiAgICAgIG5yb3cgPSAxLAogICAgICByZWxfd2lkdGhzID0gYygwLjIsIDEsIDAuMSwgMSwgMC4yKSwKICAgICAgIyBsYWJlbHMgPSBjKCJDIiwgIiIsICJEIiksCiAgICAgIHZqdXN0ID0gMC4yCiAgICApLAogICAgbmNvbCA9IDEsCiAgICByZWxfaGVpZ2h0cyA9IGMoMC4wNSwxLDAuMDUsMSkKICApLAogIAogIG5jb2wgPSAxLAogIHJlbF9oZWlnaHRzID0gYygwLjksMC4wMiwxKQopICU+JSAKICB7Z2dzYXZlKHBsb3Q9LixmaWxlbmFtZT1oZXJlKCJmaWd1cmVzLzNfNF9jb21iaW5lZC5wZGYiKSwgd2lkdGggPSA3LCBoZWlnaHQgPSA5KTsufQoKCgpgYGAKCmBgYHtyLCBmaWcud2lkdGg9NywgZmlnLmhlaWdodD03LCBtZXNzYWdlID0gRn0Kbl9kaWFnbm9zZXNfYmFyIDwtIDE1Cm5fZGlhZ25vc2VzX2FidW5kYW5jZSA8LSA1MApuX2RpYWdub3Nlc19jdW11bGF0aXZlIDwtIDUwCgphcHBseV90ZXh0X2Zvcm1hdHRpbmcgPC0gbGlzdCh0aGVtZSgKICBheGlzLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDYpLAogIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDkpLAogIGxlZ2VuZC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSA2KSwKICAjIGxlZ2VuZC5zcGFjaW5nLnkgPSB1bml0KDAuMSwgJ2NtJykKICAjIGxlZ2VuZC5oZWlnaHQgPSB1bml0KDAuMSwgJ2NtJyksCiAgbGVnZW5kLmtleS5oZWlnaHQgPSB1bml0KDAuMywgJ2NtJykKICAjIGxlZ2VuZC5rZXkuc3BhY2luZyA9IHVuaXQoMC4xLCAnY20nKQogICkpCiAgCiAgCnBsb3RfZ3JpZCgKICAKICAjIyMKICB0b3BfZGlhZ25vc2lzX3Bsb3QoZGZfZ3B0NCwgbl9kaWFnID0gbl9kaWFnbm9zZXNfYmFyKSArIAogICAgdGhlbWUoYXhpcy50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSA1LCBsaW5laGVpZ2h0ID0gMC43KSwgCiAgICAgICAgICBzdHJpcC50ZXh0ID0gZWxlbWVudF90ZXh0KHNpemUgPSA3KSwKICAgICAgICAgIGF4aXMudGl0bGUgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDkpKSArIAogICAgdGlkeXRleHQ6OnNjYWxlX3hfcmVvcmRlcmVkKGxhYmVscyA9IGN1c3RvbV9sYWJlbGVyKSwKICAjIyMKICBOVUxMLAogIHBsb3RfZ3JpZCgKICAgICAgcmFua19hYnVuZGFuY2VfcGxvdChkZl9ncHQ0LCBuX2RpYWdub3NlcyA9IG5fZGlhZ25vc2VzX2FidW5kYW5jZSkgK3RoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9IGMoMC43LDAuNykpICsgYXBwbHlfdGV4dF9mb3JtYXR0aW5nLAogICAgICBjdW11bGF0aXZlX2ZyZXF1ZW5jeV9wbG90KGRmX2dwdDQsIG5fZGlhZ25vc2VzID0gbl9kaWFnbm9zZXNfY3VtdWxhdGl2ZSwgd2lkdGggPSAwLjc1KSArIGxhYnMoeSA9IHN0cl9nbHVlKCJDb21iaW5lZCBmcmVxdWVuY3lcbm9mIHRvcCB7bl9kaWFnbm9zZXNfY3VtdWxhdGl2ZX0gZGlhZ25vc2VzIikpICsgYXBwbHlfdGV4dF9mb3JtYXR0aW5nLAogICAgICBkZl9kaXZlcnNpdHlfY2kgJT4lIAogICAgICAgIGZvcm1hdF9jcml0ZXJpYSgpICU+JSAKICAgICAgICBnZ3Bsb3QoYWVzKHggPSBjcml0ZXJpYSwgeSA9IHNoYW5ub24pKSsKICAgICAgICBnZW9tX3BvaW50KHNpemUgPSAxKSsKICAgICAgICBnZW9tX2Vycm9yYmFyKGFlcyh5bWluID0gYDIuNSVgLCB5bWF4ID0gYDk3LjUlYCksIHdpZHRoID0gMC4zKSsKICAgICAgICB0aGVtZV9idygpICsKICAgICAgICB0aGVtZShheGlzLnRleHQueCA9IGVsZW1lbnRfdGV4dChhbmdsZSA9IDQ1LCBoanVzdCA9IDEpKSArCiAgICAgICAgbGFicyh4ID0gIiIsIHkgPSAiU2hhbm5vbiBkaXZlcnNpdHkiKSArIGFwcGx5X3RleHRfZm9ybWF0dGluZywKICAgICAgbWFudWFsX2JveF9wbG90KGRmX3ByZWNpc2lvbl9zdGF0cywgd2lkdGggPSAwLjUpICsgbGFicyh5PSdCcmF5LUN1cnRpcyBzaW1pbGFyaXR5JykgKyBhcHBseV90ZXh0X2Zvcm1hdHRpbmcsCiAgICAgIG5yb3cgPSAxLCAKICAgICAgYXhpcyA9ICd0YicsCiAgICAgIGFsaWduID0gJ2gnLAogICAgICByZWxfd2lkdGhzID0gYygxLCAwLjcsIDAuNywgMC43KSwKICAgICAgbGFiZWxzID0gYyhMRVRURVJTWzI6NV0pLAogICAgICB2anVzdCA9IDAuMgogICAgKSwKICBuY29sID0gMSwKICByZWxfaGVpZ2h0cyA9IGMoMSwgMC4wNSwgMC42NSksCiAgbGFiZWxzID0gYygiQSIsIiIsIiIpCikgIAojICU+JSAKICAjIHtnZ3NhdmUocGxvdD0uLGZpbGVuYW1lPWhlcmUoImZpZ3VyZXMvM19kaWFnbm9zaXNfZGl2ZXJzaXR5LnBkZiIpLCB3aWR0aCA9IDcsIGhlaWdodCA9IDcpOy59CgoKCmBgYAoKIyBBbHRlcm5hdGl2ZSBmaW5hbCBmb3IgSUNECgpgYGB7ciwgZmlnLndpZHRoPTcuNSwgZmlnLmhlaWdodD04LjUsIG1lc3NhZ2UgPSBGfQpuX2RpYWdub3Nlc19iYXIgPC0gMTAKbl9kaWFnbm9zZXNfYWJ1bmRhbmNlIDwtIDUwCm5fZGlhZ25vc2VzX2N1bXVsYXRpdmUgPC0gNTAKCnRpdGxlX3NpemUgPC0gOQpsYWJlbF9zaXplIDwtIDYKbGVnZW5kX3hfcGFkIDwtIDQKbGVnZW5kX3lfcGFkIDwtIDIKCmFwcGx5X3RleHRfZm9ybWF0dGluZyA8LSBsaXN0KHRoZW1lKAogIGF4aXMudGV4dCA9IGVsZW1lbnRfdGV4dChzaXplID0gbGFiZWxfc2l6ZSksCiAgYXhpcy50aXRsZSA9IGVsZW1lbnRfdGV4dChzaXplID0gdGl0bGVfc2l6ZSksCiAgbGVnZW5kLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IGxhYmVsX3NpemUpLAogIHN0cmlwLnRleHQgPSBlbGVtZW50X3RleHQoc2l6ZSA9IGxhYmVsX3NpemUrMSksCiAgbGVnZW5kLmtleS5oZWlnaHQgPSB1bml0KDAuNCwgJ2NtJyksCiAgbGVnZW5kLmJveC5iYWNrZ3JvdW5kID0gZWxlbWVudF9yZWN0KGNvbG9yID0gImJsYWNrIiwgc2l6ZSA9IDEpLAogIGxlZ2VuZC5tYXJnaW4gPSBtYXJnaW4odCA9IGxlZ2VuZF95X3BhZCwgciA9IGxlZ2VuZF94X3BhZCwgYiA9IGxlZ2VuZF95X3BhZCwgbCA9IGxlZ2VuZF94X3BhZCoxLjEpLAogIGxlZ2VuZC5zcGFjaW5nLnggPSB1bml0KDAsICdjbScpLCAgICAgICAgICAgICAgICAgICAgICAgICAgICMgSG9yaXpvbnRhbCBzcGFjaW5nIGJldHdlZW4gbGVnZW5kIGl0ZW1zCiAgIyBsZWdlbmQuc3BhY2luZy55ID0gdW5pdCgwLCAnY20nKSwKICAjIGxlZ2VuZC5ib3guc3BhY2luZyA9IHVuaXQoMCwgImNtIikKICApKQoKc3RyaXBfbWFyZ2luIDwtIDEKc3RyaXBfZm9ybWF0dGluZyA8LSBsaXN0KHRoZW1lKAogIHN0cmlwLnRleHQueCA9IGVsZW1lbnRfdGV4dChtYXJnaW4gPSBtYXJnaW4odCA9IHN0cmlwX21hcmdpbiwgciA9IHN0cmlwX21hcmdpbiwgYiA9IHN0cmlwX21hcmdpbiwgbCA9IHN0cmlwX21hcmdpbikpLCAKICBzdHJpcC50ZXh0LnkgPSBlbGVtZW50X3RleHQobWFyZ2luID0gbWFyZ2luKHQgPSBzdHJpcF9tYXJnaW4sIHIgPSBzdHJpcF9tYXJnaW4sIGIgPSBzdHJpcF9tYXJnaW4sIGwgPSBzdHJpcF9tYXJnaW4pKQogICMgc3RyaXAuYmFja2dyb3VuZCA9IGVsZW1lbnRfcmVjdChtYXJnaW4gPSBtYXJnaW4odCA9IHN0cmlwX21hcmdpbiwgciA9IHN0cmlwX21hcmdpbiwgYiA9IHN0cmlwX21hcmdpbiwgbCA9IHN0cmlwX21hcmdpbikpCikpCgpwbHRfZGlhZ3MgPC0gbXVsdGlfdG9wX2RpYWdub3Npc19wbG90KGRpc3RyaWJ1dGlvbl92aXMgPSAicG9pbnRzIiwgd3JhcF93aWR0aD01OCwgbl9kaWFnID0gbl9kaWFnbm9zZXNfYmFyLAogICAgICAgICAgICAgICAgICAgICAgICAgZGZfZ3B0My41X2ljZCwgZGZfZ3B0NC4wX2ljZCwgZGZfY2xhdWRlM19oYWlrdV90MS4wX2ljZCwgCiAgICAgICAgICAgICAgICAgICAgICAgICBkZl9jbGF1ZGUzX29wdXNfdDEuMF9pY2QsIGRmX2dlbWluaTEuMF9wcm9fdDEuMF9pY2QpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwgbGVnZW5kLmRpcmVjdGlvbiA9ICJob3Jpem9udGFsIikgKwogIGFwcGx5X3RleHRfZm9ybWF0dGluZyArCiAgdGhlbWUoYXhpcy50ZXh0LnkgPSBlbGVtZW50X3RleHQoc2l6ZSA9IDYuNSkpICsKICBzdHJpcF9mb3JtYXR0aW5nICsKICAjIHRoZW1lKGxlZ2VuZC5wb3NpdGlvbiA9IGMoLTEsMCkpKwogIHRoZW1lKHBhbmVsLnNwYWNpbmcgPSB1bml0KDAsICJsaW5lcyIpKSArCiAgZ3VpZGVzKAogIGNvbG9yID0gZ3VpZGVfbGVnZW5kKG92ZXJyaWRlLmFlcyA9IGxpc3Qoc2l6ZSA9IDIpKSAgIyBJbmNyZWFzZSB0aGUgcG9pbnQgc2l6ZSBpbiB0aGUgbGVnZW5kCikKICAKCnBsdF9yYW5rIDwtIG11bHRpX3JhbmtlZF9hYnVuZGFuY2VfcGxvdChkZl9ncHQzLjVfaWNkLCBkZl9ncHQ0LjBfaWNkLCBkZl9jbGF1ZGUzX2hhaWt1X3QxLjBfaWNkLCAKICAgICAgICAgICAgICAgICAgICAgICAgICAgIGRmX2NsYXVkZTNfb3B1c190MS4wX2ljZCwgZGZfZ2VtaW5pMS4wX3Byb190MS4wX2ljZCkrCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsIGxlZ2VuZC5kaXJlY3Rpb24gPSAiaG9yaXpvbnRhbCIpICsKICBhcHBseV90ZXh0X2Zvcm1hdHRpbmcrCiAgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfbGVnZW5kKG5jb2wgPSAyKSkKCnBsdF9jdW11bGF0aXZlIDwtIG11bHRpX2N1bXVsYXRpdmVfZnJlcXVlbmN5X3Bsb3Qobl9kaWFnbm9zZXMgPSBuX2RpYWdub3Nlc19jdW11bGF0aXZlLCBkaXN0cmlidXRpb25fdmlzID0gInBvaW50cyIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGZfZ3B0My41X2ljZCwgZGZfZ3B0NC4wX2ljZCwgZGZfY2xhdWRlM19oYWlrdV90MS4wX2ljZCwgCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGZfY2xhdWRlM19vcHVzX3QxLjBfaWNkLCBkZl9nZW1pbmkxLjBfcHJvX3QxLjBfaWNkKSArCiAgdGhlbWUobGVnZW5kLnBvc2l0aW9uID0gImJvdHRvbSIsIGxlZ2VuZC5kaXJlY3Rpb24gPSAiaG9yaXpvbnRhbCIpICsKICBhcHBseV90ZXh0X2Zvcm1hdHRpbmcrCiAgZ3VpZGVzKGNvbG9yID0gZ3VpZGVfbGVnZW5kKG5jb2wgPSAyKSkgKwogIGxhYnMoeSA9ICJDb21iaW5lZCBmcmVxdWVuY3lcbm9mIHRvcCA1MCBkaWFnbm9zZXMiLCB4ID0gTlVMTCkKCnBsdF9zaGFubm9uIDwtIHRpYmJsZShtb2RlbCA9IGMoIkNoYXRHUFQgMy41IiwgIkNoYXRHUFQgNC4wIiwgIkNsYXVkZTMgSGFpa3UiLCAiQ2xhdWRlMyBPcHVzIiwgIkdlbWluaSAxLjAgUHJvIiksCiAgICAgICBkYXRhID0gbGlzdChkZl9ncHQzLjVfaWNkLCBkZl9ncHQ0LjBfaWNkLCBkZl9jbGF1ZGUzX2hhaWt1X3QxLjBfaWNkLCBkZl9jbGF1ZGUzX29wdXNfdDEuMF9pY2QsIGRmX2dlbWluaTEuMF9wcm9fdDEuMF9pY2QpKSAlPiUgCiAgbXV0YXRlKHNoYW5ub24gPSBtYXAoZGF0YSwgY2FsY3VsYXRlX3NoYW5ub24pKSAlPiUgCiAgc2VsZWN0KG1vZGVsLCBzaGFubm9uKSAlPiUgCiAgdW5uZXN0X3dpZGVyKHNoYW5ub24pICU+JSAKICBwaXZvdF9sb25nZXIoLW1vZGVsLCBuYW1lc190byA9ICJjcml0ZXJpYSIsIHZhbHVlc190byA9ICJzaGFubm9uIikgJT4lIAogIGZvcm1hdF9jcml0ZXJpYSgpICU+JSAKICBnZ3Bsb3QoYWVzKHggPSBjcml0ZXJpYSwgeSA9IHNoYW5ub24pKSsKICBzdGF0X3N1bW1hcnkoZnVuLnkgPSBtZWFuLCBhZXMoZ3JvdXAgPSBjcml0ZXJpYSksIGdlb20gPSAiY3Jvc3NiYXIiLCBzaXplID0gMC4zLCB3aWR0aCA9IDAuNzUpICsKICBnZW9tX3BvaW50KGFlcyhjb2xvciA9IG1vZGVsKSwgc2l6ZSA9IDAuNSwgcG9zaXRpb24gPSBwb3NpdGlvbl9kb2RnZSh3aWR0aCA9IDAuNzUpKSsKICB0aGVtZV9idygpICsKICBzY2FsZV9jb2xvcl9icmV3ZXIocGFsZXR0ZSA9ICJEYXJrMiIpKwogIHRoZW1lKGF4aXMudGV4dC54ID0gZWxlbWVudF90ZXh0KGFuZ2xlID0gNDUsIGhqdXN0ID0gMSkpICsKICBnZ3B1YnI6Omdlb21fcHdjKGFlcyhncm91cCA9IGNyaXRlcmlhKSwgCiAgICAgICAgICAgICAgICAgICBtZXRob2QgPSAid2lsY294LnRlc3QiLCAKICAgICAgICAgICAgICAgICAgIHAuYWRqdXN0Lm1ldGhvZCA9ICJCSCIsIAogICAgICAgICAgICAgICAgICAgaGlkZS5ucyA9IFQsIAogICAgICAgICAgICAgICAgICAgbGFiZWwgPSAicC5hZGouc2lnbmlmIiwgCiAgICAgICAgICAgICAgICAgICBicmFja2V0Lm51ZGdlLnkgPSAwLjEsIAogICAgICAgICAgICAgICAgICAgdmp1c3QgPSAwLjYsIAogICAgICAgICAgICAgICAgICAgc3RlcC5pbmNyZWFzZSA9IDAuMTQsIAogICAgICAgICAgICAgICAgICAgdGlwLmxlbmd0aCA9IDAuMDIKICAgICAgICAgICAgICAgICAgICkrCiAgbGFicyh4ID0gTlVMTCwgeSA9ICJTaGFubm9uIERpdmVyc2l0eSIsIGNvbG9yID0gIiIpKwogIGFwcGx5X3RleHRfZm9ybWF0dGluZysKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAiYm90dG9tIiwgbGVnZW5kLmRpcmVjdGlvbiA9ICJob3Jpem9udGFsIikgKwogIGd1aWRlcyhjb2xvciA9IGd1aWRlX2xlZ2VuZChuY29sID0gMikpCgpwbHRfcHJlY2lzaW9uIDwtIGRmX3ByZWNpc2lvbiAlPiUgCiAgZm9ybWF0X2NyaXRlcmlhKCkgJT4lIAogIGZvcm1hdF9tb2RlbHMoKSAlPiUKICBnZ3Bsb3QoYWVzKHggPSBjcml0ZXJpYSwgeSA9IHkpKSsKICAgIHN0YXRfc3VtbWFyeShmdW4ueSA9IG1lYW4sIGFlcyhncm91cCA9IGNyaXRlcmlhKSwgZ2VvbSA9ICJjcm9zc2JhciIsIHNpemUgPSAwLjMsIHdpZHRoID0gMC43NSkgKwogIGdlb21fcG9pbnQoYWVzKGNvbG9yID0gbW9kZWwpLCBzaXplID0gMC41LCBwb3NpdGlvbiA9IHBvc2l0aW9uX2RvZGdlKHdpZHRoID0gMC43NSkpKwogIHRoZW1lX2J3KCkrCiAgdGhlbWUoYXhpcy50ZXh0LnggPSBlbGVtZW50X3RleHQoYW5nbGU9IDQ1LCBoanVzdCA9IDEpKSsKICBsYWJzKHg9TlVMTCwgeSA9ICJBdmVyYWdlIEJyYXktQ3VydGlzXG5TaW1pbGFyaXR5IikgKwogIGdncHVicjo6Z2VvbV9wd2MobWV0aG9kID0gIndpbGNveC50ZXN0IiwgcC5hZGp1c3QubWV0aG9kID0gIkJIIiwgaGlkZS5ucyA9IFQsIGxhYmVsID0gInAuYWRqLnNpZ25pZiIsIGJyYWNrZXQubnVkZ2UueSA9IDAuMywgdmp1c3QgPSAwLjYsIHN0ZXAuaW5jcmVhc2UgPSAwLjE0LCB0aXAubGVuZ3RoID0gMC4wMikgKwogIHlsaW0oYygwLDEpKSArCiAgbGFicyhjb2xvcj1OVUxMKSsKICBzY2FsZV9jb2xvcl9icmV3ZXIocGFsZXR0ZSA9ICJEYXJrMiIpICsKICB0aGVtZShsZWdlbmQucG9zaXRpb24gPSAibm9uZSIpKwogIGFwcGx5X3RleHRfZm9ybWF0dGluZwoKCgoKZnVsbF9wbHQgPC0gcGxvdF9ncmlkKAogIAogICMjIwogIHBsdF9kaWFncywKICAjIyMKICBOVUxMLAogIHBsb3RfZ3JpZCgKICAgICAgcGx0X3JhbmssCiAgICAgIHBsdF9jdW11bGF0aXZlLAogICAgICBwbHRfc2hhbm5vbiwKICAgICAgcGx0X3ByZWNpc2lvbiwKICAgICAgbnJvdyA9IDEsIAogICAgICBheGlzID0gJ3RiJywKICAgICAgYWxpZ24gPSAnaCcsCiAgICAgIHJlbF93aWR0aHMgPSBjKDEsIDAuNywgMC43LCAwLjcpLAogICAgICBsYWJlbHMgPSBjKExFVFRFUlNbMjo1XSksCiAgICAgIHZqdXN0ID0gMC4yCiAgICApLAogIG5jb2wgPSAxLAogIHJlbF9oZWlnaHRzID0gYygxLjIsIDAuMDUsIDAuNjUpLAogIGxhYmVscyA9IGMoIkEiLCIiLCIiKQopICAKCmZ1bGxfcGx0CmBgYAoKClRoaW5ncyB0byBmaXgKLSBMZWdlbmQgcG9zaXRpb24gZm9yIEMtRQotIExlZ2VuZCB3aWR0aCBmb3IgQgotIE1vdmUgbGVnZW5kIGZvciBBIHRvIHRoZSBsZWZ0IG9mICJGcmVxdWVuY3k/IgotIFJhbmsgcGxvdCBsaW5lIHdlaWdodAoKYGBge3J9Cmdnc2F2ZShwbG90PWZ1bGxfcGx0LGZpbGVuYW1lPWhlcmUoImZpZ3VyZXMvM19kaWFnbm9zaXNfZGl2ZXJzaXR5LnBkZiIpLCB3aWR0aCA9IDcuNSwgaGVpZ2h0ID0gNy41KQpgYGAKCnNldF90YWJsZV9wcm9wZXJ0aWVzKG9wdHNfcGRmID0gbGlzdCh0YWJjb2xzZXAgPSAwKSkKYGBge3J9CnNldF9mbGV4dGFibGVfZGVmYXVsdHMoZm9udHNfaWdub3JlPVRSVUUpCgptdWx0aV9kaWFnbm9zaXNfcmFua190YWJsZShzZWFyY2hfcGF0dGVybiA9ICJUNzhcXC4yIHxENDdcXC4wMiB8RDg5XFwuNDEgfEQ4OVxcLjQ5IHxEODlcXC40ICIsCiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgZGZfZ3B0My41X2ljZCwgZGZfZ3B0NC4wX2ljZCwgZGZfY2xhdWRlM19oYWlrdV90MS4wX2ljZCwgZGZfY2xhdWRlM19vcHVzX3QxLjBfaWNkLCBkZl9nZW1pbmkxLjBfcHJvX3QxLjBfaWNkKSAlPiUgCiAgZmxleHRhYmxlKCkgJT4lIAogIHdpZHRoKHdpZHRoID0gMikgJT4lIAogIGZvbnRzaXplKHNpemUgPSA5KSAlPiUgCiAgZm9udHNpemUoc2l6ZSA9IDEwLCBwYXJ0ID0gImhlYWRlciIpICU+JSAKICBwYWRkaW5nKHBhZGRpbmcgPSAwKSAlPiUgCiAgYWxpZ24oaiA9IDI6MywgYWxpZ24gPSAiY2VudGVyIiwgcGFydCA9ICJhbGwiKSAlPiUgCiAgc2V0X3RhYmxlX3Byb3BlcnRpZXMob3B0c19wZGYgPSBsaXN0KGFycmF5c3RyZXRjaCA9IDEuMjUpKSAlPiUgCiAge3ByaW50KC4sIHByZXZpZXcgPSAicGRmIik7Ln0KYGBgCgoK